async/awaitによるマルチスレッド処理

2017-06-09

返り値のないメソッドの場合

        private async void btnStart_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start:" + DateTime.Now.ToString("HH:mm:ss.ff"));

            await Count();

            Console.WriteLine("Finish:" + DateTime.Now.ToString("HH:mm:ss.ff"));
        }

        private async Task Count()
        {
            int intValue = 1;

            await Task.Run(() =>
            {
                for(int intCount = 0; intCount < 15; intCount++)
                {
                    intValue *= 2;
                    Console.WriteLine(intValue);

                    System.Threading.Thread.Sleep(100);
                }
            });
        }

 

別スレッドからキャンセル処理を行う場合は下記のようになる。

        // トークン
        private CancellationTokenSource objToken = null;

        private async void btnStart_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start:" + DateTime.Now.ToString("HH:mm:ss.ff"));

            await Count();

            Console.WriteLine("Finish:" + DateTime.Now.ToString("HH:mm:ss.ff"));
        }

        private async Task Count()
        {
            int intValue = 1;

            objToken = new CancellationTokenSource();

            await Task.Run(() =>
            {
                for(int intCount = 0; intCount < 15; intCount++)
                {
                    // キャンセルフラグが立っていたら処理を抜ける
                    if(objToken.IsCancellationRequested == true)
                    {
                        return;
                    }

                    intValue *= 2;
                    Console.WriteLine(intValue);

                    System.Threading.Thread.Sleep(100);
                }
            }, objToken.Token);
        }

        /// <summary>
        /// キャンセル処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            if(objToken != null)
            {
                objToken.Cancel();
            }
        }

また、IsCancellationRequested ではなく ThrowIfCancellationRequested を用いることで、
例外として処理することもできる。

        // トークン
        private CancellationTokenSource objToken = null;

        private async void btnStart_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start:" + DateTime.Now.ToString("HH:mm:ss.ff"));

            try
            {
                await Count();
                Console.WriteLine("Finish:" + DateTime.Now.ToString("HH:mm:ss.ff"));
            }
            catch (OperationCanceledException exCanceled)
            {
                // キャンセル時
                Console.WriteLine("Canceled:" + DateTime.Now.ToString("HH:mm:ss.ff"));
            }
        }

        private async Task Count()
        {
            try
            {
                int intValue = 1;

                objToken = new CancellationTokenSource();

                await Task.Run(() =>
                {
                    try
                    {
                        for (int intCount = 0; intCount < 15; intCount++)
                        {
                            // キャンセルフラグが立っていたらOperationCanceledExceptionを発生させる
                            objToken.Token.ThrowIfCancellationRequested();

                            intValue *= 2;
                            Console.WriteLine(intValue);

                            System.Threading.Thread.Sleep(100);
                        }
                    }
                    catch (OperationCanceledException exCanceled)
                    {
                        // キャンセル時
                        throw (exCanceled);
                    }
                }, objToken.Token);
            }
            catch (Exception ex)
            {
                throw (ex);
            }
        }

        /// <summary>
        /// キャンセル処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (objToken != null)
            {
                objToken.Cancel();
            }
        }

 

 

返り値のあるメソッドの場合

        private async void btnStart_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Start:" + DateTime.Now.ToString("HH:mm:ss.ff"));

            int intResult = await Count();

            Console.WriteLine("Total:" + intResult);

            Console.WriteLine("Finish:" + DateTime.Now.ToString("HH:mm:ss.ff"));
        }

        private async Task<int> Count()
        {
            int intValue = 1;
            
            int intResult = await Task.Run(() =>
            {
                int intSum = 0;

                for(int intCount = 0; intCount < 15; intCount++)
                {
                    intValue *= 2;
                    Console.WriteLine(intValue);

                    intSum += intValue;

                    System.Threading.Thread.Sleep(100);
                }

                return intSum;
            });

            return intResult;
        }

 

また、VB.NETの場合は下記のようになる(返り値のないメソッド)

    Private Async Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
        Debug.Print("Start:" + DateTime.Now.ToString("HH:mm:ss.ff"))

        Await Count()

        Debug.Print("Finish:" + DateTime.Now.ToString("HH:mm:ss.ff"))
    End Sub

    Private Async Function Count() As Task
        Dim intValue As Integer = 1

        Await Task.Run(Sub()
                           For intCount = 0 To 14
                               intValue *= 2
                               Debug.Print(intValue)

                               System.Threading.Thread.Sleep(100)
                           Next
                       End Sub)
    End Function