[非同期プログラミングを知っておく必要があります]-タスクベースの非同期モード(TAP)


本特集の概要
  • 引用
  • TAPとは何か--タスクベースの非同期モード紹介
  • TAPの使用方法-タスクベースの非同期モードを使用して非同期プログラミング
  • TAPとAPMまたはEAPは変換できますか?——他の非同期モードへの変換
  • 小結
  • 一、引用
    前の2つのテーマで紹介します.NET 1.0のAPMと.NET 2.0のEAPは、前の2つのモードを使って非同期プログラミングをしているとき、皆さんは多少実現が面倒だと感じているに違いありません.まず、APMを使うときは、まずコールバック方法を包装するための依頼を定義する必要があります.これは少し煩わしいですが、EAPを使うときは、CompletedイベントやProgressイベントを実現する必要があります.上の2つの実現方式はいずれも少し煩雑な感じがして、同時にマイクロソフトもこの点を意味して、だから.NET 4.0では、主にSystemを使用するタスクベースの非同期モードという新しい非同期モードが提案されている.Threading.Tasks.TaskとTaskクラスは非同期プログラミングを完成するために、前の2つの非同期モードに比べて、TAPは非同期プログラミングモードをより簡単にする(ここではTaskというクラスの使用に注目する必要があるため)、同時にTAPもマイクロソフトが推奨する非同期プログラミングモードであり、以下は具体的に以下のテーマの内容を共有する.
    二、TAPとは何か——タスクベースの非同期モードの紹介
    タスクベースの非同期モード(Task-based Asynchronous Pattern,TAP)がマイクロソフトに推奨されているのは、主にその使用が簡単で、タスクベースの非同期モードは単一の方法で非同期操作の開始と完了を表すが、非同期プログラミングモデル(APM)はBeginXxxとEndXxxの2つの方法を求めて非同期操作の開始と完了をそれぞれ表す(このように使用すると複雑になる).しかしながら、イベントベースの非同期モード(EAP)は、Async接尾辞を有する方法および1つまたは複数のイベント、イベントハンドラ、およびイベントパラメータを必要とする.ここを見て、私たちはどのように区別するかという疑問があります.NETクラスライブラリのクラスはタスクベースの非同期モードを実現していますか?この識別方法は簡単で、クラスにTaskAsyncが接尾辞として存在する方法を見ると、クラスがTAPを実現したことを表し、タスクベースの非同期モードも同様に非同期操作のキャンセルと進捗の報告の機能をサポートしているが、この2つの実現はEAPで実現したほど複雑ではない.EAPのクラスを自分で実現する場合、複数のイベントとイベントハンドラの委任タイプとイベントのパラメータを定義する必要があります(詳細は、前のトピックのBackgroundWorkerプロファイリングセクションを参照できます)が、TAP実装では、非同期メソッド内でこのパラメータのIsCancellationRequestedプロパティを監視するため、非同期メソッドにCancellationTokenパラメータを転送する必要があります.非同期メソッドがキャンセル要求を受信すると、非同期メソッドは実行を終了します(具体的には、反射ツールを使用してWebClientのDownloadDataTaskAsyncメソッドを表示するとともに、タスクベースの非同期モードを実装する私の後の部分を参照してください).TAPでは、IProgressインタフェースを通じて進捗報告の機能を実現することができ、具体的な実装は私の後のプログラム部分を参照することができます.
    まだ見つかっていません.NETクラスライブラリではタスクベースの非同期モードのどのクラスが進捗レポートを提供する機能を実現しているのか,以下ではこの実装を実証し,このプログラムのハイライトでもあるとともに,TAPベースの非同期モードを自分で実現することでさらに理解する.
    三、どのようにTAPを使用するか——タスクベースの非同期モードを使用して非同期プログラミングを行う
    上記の説明を見て、タスクベースの非同期モードの非同期メソッドをどのように自分で実現するかを知りたいのではないでしょうか.また、このメソッドだけで非同期操作のキャンセルと進捗報告の機能を完成させることができることを望んでいます(EAPでは他のイベントを実装し、イベントパラメータのタイプを定義する必要があるため、このような実現は複雑すぎます).次に、上記のトピックで実装されたプログラムに基づいて、タスクベースの非同期モードで完了します.次に、独自の非同期メソッドを実装します(進捗レポートと非同期操作のキャンセルを1つのメソッドで完了できる機能がハイライトされています).
    //  Download File
            // CancellationToken             
            // progress        
            private void DownLoadFile(string url, CancellationToken ct, IProgress progress)
            {
                HttpWebRequest request = null;
                HttpWebResponse response = null;
                Stream responseStream = null;
                int bufferSize = 2048;
                byte[] bufferBytes = new byte[bufferSize];
                try
                {
                    request = (HttpWebRequest)WebRequest.Create(url);
                    if (DownloadSize != 0)
                    {
                        request.AddRange(DownloadSize);
                    }
                    response = (HttpWebResponse)request.GetResponse();
                    responseStream = response.GetResponseStream();
                    int readSize = 0;
                    while (true)
                    {
                        //              
                        if (ct.IsCancellationRequested == true)
                        {
                            MessageBox.Show(String.Format("    ,        :{0}
    : {1} ", downloadPath, DownloadSize)); response.Close(); filestream.Close(); sc.Post((state) => { this.btnStart.Enabled = true; this.btnPause.Enabled = false; }, null); // break; } readSize = responseStream.Read(bufferBytes, 0, bufferBytes.Length); if (readSize > 0) { DownloadSize += readSize; int percentComplete = (int)((float)DownloadSize / (float)totalSize * 100); filestream.Write(bufferBytes, 0, readSize); // progress.Report(percentComplete); } else { MessageBox.Show(String.Format(" , :{0}, : {1} ", downloadPath, totalSize)); sc.Post((state) => { this.btnStart.Enabled = false; this.btnPause.Enabled = false; }, null); response.Close(); filestream.Close(); break; } } } catch (AggregateException ex) { // Cancel OperationCanceledException // OperationCanceledException ex.Handle(e => e is OperationCanceledException); } }

    これにより、上記の1つの方法だけで、前のトピックでファイルのダウンロードプログラムを完了することができ、ダウンロードボタンのイベントハンドラでこの方法を呼び出し、一時停止ボタンのイベントハンドラでCancellationTokenSourceを呼び出すだけでよい.Cancelメソッドで、具体的なコードは次のとおりです.
    // Start DownLoad File
            private void btnStart_Click(object sender, EventArgs e)
            {
                filestream = new FileStream(downloadPath, FileMode.OpenOrCreate);
                this.btnStart.Enabled = false;
                this.btnPause.Enabled = true;
                filestream.Seek(DownloadSize, SeekOrigin.Begin);
                //                 
                sc = SynchronizationContext.Current;
                cts = new CancellationTokenSource();
                //              Task。
                task = new Task(() => Actionmethod(cts.Token), cts.Token);
                //    Task,          TaskScheduler    。
                task.Start();
                //await DownLoadFileAsync(txbUrl.Text.Trim(), cts.Token,new Progress(p => progressBar1.Value = p));
            }
            //         
            private void Actionmethod(CancellationToken ct)
            {
                //         Post     UI         
                DownLoadFile(txbUrl.Text.Trim(), ct, new Progress(p =>
                    {
                        sc.Post(new SendOrPostCallback((result)=>progressBar1.Value=(int)result),p);
                    }));
            }
            // Pause Download
            private void btnPause_Click(object sender, EventArgs e)
            {
                //         
                cts.Cancel();
            }

    次に、タスクベースの非同期モードの実装効果について説明します.
    OKボタンをクリックすると、Downloadボタンが再び利用可能になります.このとき、Downloadボタンをクリックしてダウンロードしてダウンロードすることができます.ダウンロードが完了すると、ダウンロード完了ポップアップボックスがダウンロードされ、実行結果は以下の通りです.
    四、TAPとAPMまたはEAPは変換できますか?他の非同期モードへの変換
    上のプログラムコードから、タスクベースの非同期モードは確かに前の2つの非同期モードよりも簡単に使用できることが明らかになった.NET Framework 4.0から、マイクロソフトはTAPを使用して非同期プログラミングを実現することを推奨している.ここでは、APMまたはEAPで実現したプログラムがTAPで実現する問題にどのように移行するかについて説明する.NET Framwworkは彼らの間の転換にもよく支持した.
    4.1 APMをTAPに変換
    システムでThreading.TasksネーミングスペースにはTaskFactory(タスクエンジニアリング)クラスがあり、このクラスのFromAsyncメソッドを利用してAPMをTAPに変換することができます.次に、タスクベースの非同期モードで非同期プログラミングモデルブログの例を実現します.
    //              
            #region   APM      
            private void APMWay()
            {
                WebRequest webRq = WebRequest.Create("http://msdn.microsoft.com/zh-CN/");
                webRq.BeginGetResponse(result =>
                {
                    WebResponse webResponse = null;
                    try
                    {
                        webResponse = webRq.EndGetResponse(result);
                        Console.WriteLine("        : " + webResponse.ContentLength);
                    }
                    catch (WebException ex)
                    {
                        Console.WriteLine("    ,     : " + ex.GetBaseException().Message);
                    }
                    finally
                    {
                        if (webResponse != null)
                        {
                            webResponse.Close();
                        }
                    }
                }, null);
            }
            #endregion
            #region   FromAsync   APM   TAP
            private void APMswitchToTAP()
            {
                WebRequest webRq = WebRequest.Create("http://msdn.microsoft.com/zh-CN/");
                Task.Factory.FromAsync(webRq.BeginGetResponse, webRq.EndGetResponse, null, TaskCreationOptions.None).
                    ContinueWith(t =>
                    {
                        WebResponse webResponse = null;
                        try
                        {
                            webResponse = t.Result;
                            Console.WriteLine("        : " + webResponse.ContentLength);
                        }
                        catch (AggregateException ex)
                        {
                            if (ex.GetBaseException() is WebException)
                            {
                                Console.WriteLine("    ,     : " + ex.GetBaseException().Message);
                            }
                            else
                            {
                                throw;
                            }
                        }
                        finally
                        {
                            if (webResponse != null)
                            {
                                webResponse.Close();
                            }
                        }
                    });
            }
            #endregion

    上のコードはAPMの原始的な実現方式とどのようにFromAsync方法を使ってAPMの実現方式をTAPの実現方法に変換するかを実証して、この2つの方式を一緒に置いて、1つはみんなが1つの対比をすることを助けることができて、みんなにAPMとTAPの変換をもっと理解させて、2つはみんなも上の対比を通じてTAPとAPMの違いを理解することができます.
    4.2 EAPをTAPに変換
    APMの処理はTAPで実現できるようにアップグレードできますが、EAPについてもTAPに変換できる方法があります.次のコードでは、EAPをTAPに変換する方法を示します.
    #region  EAP   TAP     
                // webClient            (EAP)
                WebClient webClient = new WebClient();
                //   TaskCompletionSource     Task  
                TaskCompletionSource tcs = new TaskCompletionSource();
                //   string     ,WebClient     DownloadStringCompleted  
                webClient.DownloadStringCompleted += (sender, e) =>
                {
                    //        GUI      
                    //   Task  
                    if (e.Error != null)
                    {
                        //      Tasks.Task   Tasks.TaskStatus.Faulted  
                        tcs.TrySetException(e.Error);
                    }
                    else if (e.Cancelled)
                    {
                        //      Tasks.Task   Tasks.TaskStatus.Canceled  
                        tcs.TrySetCanceled();
                    }
                    else
                    {
                        //      Tasks.Task   TaskStatus.RanToCompletion  。
                        tcs.TrySetResult(e.Result);
                    }
                };
                //  Task        Task,  Task   
                //          GUI     ,     TaskContinuationOptions.ExecuteSynchronously
                //         ,                
                tcs.Task.ContinueWith(t =>
                {
                    if (t.IsCanceled)
                    {
                        Console.WriteLine("      ");
                    }
                    else if (t.IsFaulted)
                    {
                        Console.WriteLine("    ,     :" + t.Exception.GetBaseException().Message);
                    }
                    else
                    {
                        Console.WriteLine(String.Format("     ,   :{0}", t.Result));
                    }
                }, TaskContinuationOptions.ExecuteSynchronously);
                //       
                webClient.DownloadStringAsync(new Uri("http://msdn.microsoft.com/zh-CN/"));
                #endregion

    五、まとめ
    このテーマはTAPの内容についてここまで紹介して、このテーマは主に1つのファイルダウンロードプログラムを実現してタスクに基づく非同期モードがもたらす簡便さを述べて、これも.NET 4.0でTAPが提案された理由としては,最後にTAPとAPMとEAPモードの間の変換を紹介したが,この部分では,従来の非同期実装がどのように新しい非同期モードへの移行を実現したのか,それらの変換実装コードからもそれらの違いを比較できることが明らかになった.しかしNET 4.5では、マイクロソフトが非同期プログラミングをよりよくサポートしています.asyncとawaitの2つのキーワードを提供しています.この2つのキーワードは、同期プログラミングのように非同期プログラミングを簡単にし、非同期プログラミングを実現するために直面している委託コールバック、スレッド間アクセスコントロールなどの問題を徹底的に変えました.具体的には、次のテーマでご紹介します.