2013-04-17 11 views
137

私が読んだすべてのブログ記事は、C#で非同期メソッドを使用する方法を説明していますが、何らかの奇妙な理由のため、消費する独自の非同期メソッドを構築する方法を決して説明しません。だから私はこのコードを持っている今、それは私の方法を消費:C#でどのように非同期メソッドを作成しますか?

private async void button1_Click(object sender, EventArgs e) 
{ 
    var now = await CountToAsync(1000); 
    label1.Text = now.ToString(); 
} 

そして私はCountToAsyncあり、この方法を書いた:

private Task<DateTime> CountToAsync(int num = 1000) 
{ 
    return Task.Factory.StartNew(() => 
    { 
     for (int i = 0; i < num; i++) 
     { 
      Console.WriteLine("#{0}", i); 
     } 
    }).ContinueWith(x => DateTime.Now); 
} 

を書くための最良の方法、この、Task.Factoryの使用ですが非同期メソッド、または私はこれを別の方法で記述する必要がありますか?

+1

私たちはあなたが何をしているのか分からないので、それを行う最良の方法は何ですか?フラクタルイメージの非同期計算を行う方法は、ファイルの非同期ダウンロードとは大きく異なります。 –

+14

私はメソッドの構造化方法に関する一般的な質問をしています。私はちょうど私の既に同期メソッドを非同期メソッドに変え始めるところを知りたがっています。 –

+2

一般的な同期メソッド* do *、*なぜ非同期*にしたいのですか? –

答えて

172

複雑さが必要な場合を除き、StartNewはお勧めできません。

あなたの非同期メソッドは、他の非同期メソッドに依存している場合は、最も簡単な方法はasyncキーワードを使用することです:

private static async Task<DateTime> CountToAsync(int num = 10) 
{ 
    for (int i = 0; i < num; i++) 
    { 
    await Task.Delay(TimeSpan.FromSeconds(1)); 
    } 

    return DateTime.Now; 
} 

あなたの非同期メソッドは、CPUの仕事をしている場合は、Task.Runを使用する必要があります。

private static async Task<DateTime> CountToAsync(int num = 10) 
{ 
    await Task.Run(() => ...); 
    return DateTime.Now; 
} 

私のasync/await introが参考になる場合があります。

+3

@Stephen: "あなたの非同期メソッドが他の非同期メソッドに依存している場合" - それは大丈夫ですが、そうでない場合はどうなりますか? BeginInvokeをいくつかのコールバックコードで呼び出すコードをラップしようとしたらどうでしょうか? – Ricibob

+0

@Ricibob: 'BeginInvoke'をラップするには' TaskFactory.FromAsync'を使うべきです。あなたは "コールバックコード"について何を意味するか分かりません。コードであなた自身の質問を投稿してください。 –

+0

@Stephen:ありがと - はいTaskFactory.FromAsyncは私が探していたものです。 – Ricibob

-8

ちょうどあなたのコードに単語のカップルを追加 - 「非同期」と「待つ」:

private async Task<DateTime> CountToAsync(int num = 1000) 
{ 
    return await Task.Factory.StartNew(() => 
    { 
     for (int i = 0; i < num; i++) 
     { 
      Console.WriteLine("#{0}", i); 
     } 
    }).ContinueWith(x => DateTime.Now); 
} 
+3

'await'を使用すると、実際にコードを単純化するために' await'を利用する受け入れられた答えとは異なり、これまでになかったコードに何も追加されませんでした。あなたの解決策は*それを取り除くのではなく、複雑さを加える。 – Servy

+1

これをコードに追加する理由を説明してください。私は何の利益も見られない。 – Florian

2

あなたのメソッドの内部で非同期/のawaitを使用したいのですが、まだそれを「飾る」しなかった場合外部から待つキーワードを使用できるようにするようにTaskCompletionSource.cs

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ =>   
    { 
     try 
     { 
      T result = function(); 
      tcs.SetResult(result); 
     } 
     catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
} 

From herehere

タスクでこのようなパラダイムをサポートするには、タスクファサードを保持する方法と、タスクとして任意の非同期操作を参照する機能が必要ですが、提供している基盤となるインフラストラクチャのルールに従ってそのタスクの有効期間を制御する必要があります非同期を実行し、それほどコストがかからないようにします。これがTaskCompletionSourceの目的です。

私は、.NETソースなどでも使用されています。 WebClient.cs

[HostProtection(ExternalThreading = true)] 
    [ComVisible(false)] 
    public Task<string> UploadStringTaskAsync(Uri address, string method, string data) 
    { 
     // Create the task to be returned 
     var tcs = new TaskCompletionSource<string>(address); 

     // Setup the callback event handler 
     UploadStringCompletedEventHandler handler = null; 
     handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadStringCompleted -= completion); 
     this.UploadStringCompleted += handler; 

     // Start the async operation. 
     try { this.UploadStringAsync(address, method, data, tcs); } 
     catch 
     { 
      this.UploadStringCompleted -= handler; 
      throw; 
     } 

     // Return the task that represents the async operation 
     return tcs.Task; 
    } 

は最後に、私は次のようにも有用であることが判明:

私はこの質問にすべての時間を聞かれます。その意味は、外部リソースへのI/O呼び出しでブロックされているスレッドがあるはずだということです。したがって、非同期コードは要求スレッドを解放しますが、システム内の別のスレッドを犠牲にして、正しく機能しますか?いいえ、まったくありません。なぜ非同期要求が拡大するのか理解するために、私は非同期I/O呼び出しの(単純化された)例をトレースします。要求がファイルに書き込む必要があるとしましょう。要求スレッドは、非同期書き込みメソッドを呼び出します。 WriteAsyncは、BCL(Base Class Library)によって実装され、非同期I/Oの完了ポートを使用します。したがって、WriteAsync呼び出しは、非同期ファイル書き込みとしてOSに渡されます。その後、OSはドライバスタックと通信し、I/O要求パケット(IRP)に書き込むためにデータを渡します。デバイスドライバがIRPを即座に処理できない場合は、デバイスドライバが非同期に処理する必要があります。したがって、ドライバはディスクに書き込みを開始するように指示し、OSに「保留中の」応答を返します。 OSはその "ペンディング"応答をBCLに渡し、BCLは不完全なタスクを要求処理コードに戻します。要求処理コードは、そのメソッドから不完全なタスクを返すなどのタスクを待機します。最後に、要求処理コードはASP.NETに不完全なタスクを返すようになり、要求スレッドは解放されてスレッドプールに戻ります。

Introduction to Async/Await on ASP.NET

ターゲットは(というよりも応答性)スケーラビリティを向上させることであるならば、それはすべてのことを行う機会を提供し、外部I/Oの存在に依存しています。

+0

[Task.Run実装](https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,298c51c20d5a4fad)の上にコメントが表示されている場合は、例: _指定された作業がThreadPool上で実行され、その作業用のタスクハンドルを返します。あなたは実際に同じことをします。私は、Task.Runが、CancelationTokenを内部的に管理し、スケジュール設定と実行オプションで最適化を行うため、より良くなると確信しています。 – unsafePtr

関連する問題