2016-04-22 7 views
1

複数の非同期メソッドを並行して実行し、それらのすべてを待つ必要があります。 (Task.WhenAll)これらのメソッドでは、Dictionary()のような共有リソースにアクセスする必要があります。スレッドセーフである必要がありますか?同時非同期タスクから共有リソースに安全にアクセスできますか? (C#)

私は以下の2つの例を実行しようとしましたが、両方ともマルチスレッド(インターリーブされたメッセージ/日付)を意味するようです。 http://rextester.com/AEH56431http://rextester.com/YEB50034

この画像に何か問題がありますか?誰でも確認/拒否できますか? C#Concurrency Masterが見えませんでした。編集:実際にスティーブンスは彼のasync intro blogのスレッディングモデルについて話しています。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text.RegularExpressions; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Rextester 
{ 
    public class Program 
    { 
     static public async Task run2() 
     { 
      Console.WriteLine("START"); 

      await Task.WhenAll(steps(1),steps(2),steps(3),steps(4)); 

      Console.WriteLine("STOP"); 
     } 


     static public async Task steps(int i) { 
      await Task.Delay(100*i); 
      Console.WriteLine("step"+i+".1"); 
      Thread.Sleep((5-i)*300); 
      Console.WriteLine("step"+i+".2"); 
      Thread.Sleep((5-i)*300); 
      Console.WriteLine("step"+i+".3"); 
      Thread.Sleep((5-i)*300); 
      Console.WriteLine("step"+i+".4"); 
     } 

     public static void Main(string[] args) 
     { 
      run2().Wait(); 
     } 

    } 
} 

と結果だった:

START 
step1.1 
step2.1 
step3.1 
step4.1 
step4.2 
step3.2 
step4.3 <-- multithreading? (2 isn't done) 
step2.2 
step1.2 
step4.4 
step3.3 <-- multithreading? 
step2.3 
step3.4 
step1.3 <-- multithreading? 
step2.4 
step1.4 
STOP 

次に別の変形:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text.RegularExpressions; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Text; 

namespace Rextester 
{ 
    public class Program 
    { 
     static public async Task run() 
     { 
      Console.WriteLine("START"); 

      await Task.WhenAll(steps(1),steps(2),steps(3),steps(4)); 

      Console.WriteLine("\nSTOP"); 
     } 

     static public async Task steps(int i) { 
      var a = new StringBuilder(); 

      await Task.Delay(100*i); // This is to force to run in Async mode. 

      // following is a block of code with (hopefully) no "async waits". Just CPU-bound (Thread.Sleep should be blocking the thread I think?) 

      a.Append("\nSTART ["+Thread.CurrentThread.ManagedThreadId+"]"); 
      a.Append("\nstep "+i+".1 >"+DateTime.Now.ToString("mm:ss.fff")); 
      Thread.Sleep((5-i)*400); 
      a.Append("\nstep "+i+".2 >"+DateTime.Now.ToString("mm:ss.fff")); 
      Thread.Sleep((5-i)*400); 
      a.Append("\nstep "+i+".3 >"+DateTime.Now.ToString("mm:ss.fff")); 
      Thread.Sleep((5-i)*400); 
      a.Append("\nstep "+i+".4 >"+DateTime.Now.ToString("mm:ss.fff")); 
      a.Append("\nSTOP"); 

      Console.WriteLine(a.ToString()); 
     } 

     public static void Main(string[] args) 
     { 
      run().Wait(); 
     } 

    } 
} 

次を出力します

START 

START [9] 
step 4.1 >57:08.485 
step 4.2 >57:08.891 
step 4.3 >57:09.298 
step 4.4 >57:09.704 
STOP 

START [8] 
step 3.1 >57:08.391 
step 3.2 >57:09.204 
step 3.3 >57:10.017 
step 3.4 >57:10.830 
STOP 

START [7] 
step 2.1 >57:08.297 
step 2.2 >57:09.501 
step 2.3 >57:10.705 
step 2.4 >57:11.908 
STOP 

START [6] 
step 1.1 >57:08.203 
step 1.2 >57:09.814 
step 1.3 >57:11.424 
step 1.4 >57:13.034 
STOP 

STOP 
+1

何かをデモしたい場合は、 'CurrentThread.ManagedId'を表示してください。 –

+0

okidoki。 Thread.CurrentThread.ManagedThreadIdが見つかりましたが、ManagedIdは見つかりませんでした。すべてが異なるManagedThreadId – Bernard

+1

質問が大幅に変更されたことに注意してください。編集履歴を参照してください。 – usr

答えて

0

これらの "手順" を実行することができます並行して。非同期関数は、完了していない待ち行列で最初に待機するときに戻ります。ここでは、それはawait Task.Delay(100*i);です。 Delayの続きは、スレッドプール上で実行されます。このため、遅延によって残りのコードがスレッドプールに移動します。

これがなければ、Delayはすべて(これは他のスリープを含めて)連続しているはずです。

本当に、このコードは偶然のように動作します。すべて非同期にブロックすると、同時に実行されることがはっきりします。また、強制への呼び出しをTask.Runと同時に挿入し、それが意図的であることを記録することもできます。

また、async IO(Task.Delayを含む)は、進行中のワーカースレッドを消費しないことにも注意してください。スレッドをまったく消費しません。

Delayコールを削除し、コードを1ステップずつ実行することを教えてください。すべてのことがメインスレッドで実行されるので、これは簡単です。

+0

申し訳ありませんが、私は本当に複数のタスクを並行して実行したいと思っています(並列に複数のWebサービスを呼び出すのがユースケースです)。しかし、C#コードの部分が(*マルチスレッド*のように)同時に実行されるかどうかを知る必要があります。か否か。質問を明確にするように更新します。 – Bernard

+1

多分あなたは待っているとスレッドを開始しないことに気付かないでしょうか?多分それが問題です。私はあなたの編集を待つでしょう。 – usr

+0

asyncはスレッドを開始しません。しかし、コードは別のスレッドに実行される可能性があります。多分これらのスレッドがたくさんありますか? (すべてのスレッドが1つしかないnodejsとは異なります)。 "Thread.Sleep()"を使用してスレッドを「ホールド」し、実際にスレッドがすべて同時に実行されているかどうかを確認します。それらが同時に実行されていて、マルチスレッドを意味する "待ち時間/タスク"がない場合は、私は(?)と仮定します。 2番目の例では、StringBuffer()を使用してCPUバインド(I/Oバインドではありません)しています。 – Bernard

1

は、それがマルチスレッド(インターリーブメッセージ/日付)である

ものは、それが同時だことを暗示することを示唆しています。ステップのそれぞれが個別に常にシーケンシャルであることを

await Task.WhenAll(steps(1),steps(2),steps(3),steps(4)) 

注:そして、実際には、Task.WhenAllを使用して、この行は、非同期の並行処理を行う方法です。したがって、非同期であっても、stepsの各実行は「線形に」進行します。つまり、1.1は常に1.2の前にあり、1.3などに先行します。したがって、1.xのすべてが順番になります。2.xなどとなります。しかし、複数の同時実行がstepsであり、それらはインターリーブすることができます。

マルチスレッドがあるかどうかにかかわらず、これは当てはまります。この場合(コンソールアプリケーション)、SynchronizationContextまたはTaskSchedulerが存在しないため、すべてawaitがスレッドプールスレッドで再開しています。同じコードが単一スレッドのシナリオ(UIスレッドなど)で実行された場合、同じスレッド上で同じ順次およびインターリーブされた動作がすべて表示されます。

+0

うわー!回答ありがとうございます!だから、マルチスレッドがあるという事実は、あなたが言うように、Taskingシステムの実装の詳細だけが異なっていてもよいということです。ちょうど明確にするために: "UIスレッド"のケースは、私が想定しているWindowed AppやXamarin-on-Androidのようなものでしょうか?しかし、ASP.NET用ではないでしょうか? – Bernard

+0

少し詳細ですが、ステップ(1.1,1.2,1.3,1.4)はTask.Delay()ではなくThread.Sleep()で区切られていません。これは重要な違いです。したがって、「UIスレッド」(単一スレッドのシナリオ)では、決してインターリーブしません。これは正しいです? – Bernard

+0

@Bernard:実装の詳細ではありません。それは十分に文書化されている。私は詳細に行く[非同期イントロ](http://blog.stephencleary.com/2012/02/async-and-await.html)のブログ記事を持っています。はい、UIはGUIアプリケーションを意味し、ASP.NETは意味しません。 UIスレッドのシナリオでは、 'Thread.Sleep'はUIスレッドをブロックします。 –

関連する問題