2016-10-08 4 views
2

SemaphoreSlimTask.Run()を使用してマルチスレッドを実行するコードを作成しようとしています。ここでなぜこのTask.Runラムダは同期的に実行されますか?

は抜粋です:完全かつsemaphore.Release()いくつかのタスクがスレッドを解放するまで、私が起こることを期待したもの

var semaphore = new SemaphoreSlim(50, 50); 
foreach (var item in collection) 
{ 
    semaphore.Wait(); 

    Task.Run(() => 
    { 
     item.Property = DoTheThing(item.AnotherValue).Result; 
     db.SaveChanges(); 
     semaphore.Release(); 
    }); 
} 

は50個のタスクがキューに入れられ、その後semaphore.Wait()されるだろうということであることでキックとforeachループを開催しますより多くをキューに入れることができます。

実際には、コードは同期して順番に実行されます。私はここで何が欠けていますか?私はTask.Run()が新しいスレッドでラムダコードを開始したと思いましたか?

+1

'Task.Run()'はあなたが待っていない 'Task'オブジェクトを返します。 – siride

+0

@siride正確には、SemaphoreSlimを使用して、開始するタスクの数を制御しています。私は非ラムダ式でこのパターンを使用していますが、ラムダ式では何らかの理由で動作せず、シングルスレッドのみが実行されます – Guerrilla

+1

@Guerrilla:私はまだこれに新しいですが、私はあなたが望むかもしれないと思いますタスクの配列を作成し、その配列に 'Task.WhenAll()'を使用することです。ラムダ内でセマフォ待機を行うことができます。 – siride

答えて

0

はここを見てみましょう:基本的にWhen would I use Task.Yield()?

Task.Run()その中にコードが非同期的に実行することを保証するものではありません。あなたはこれをしなければならないことを確実にしたい場合:

Task.Run(async() 
{ 
    await Task.Yield(); 
    ... 
}); 
0

あなたの方法は、次のバージョンで試してくださいAsyncであると仮定すると:

var semaphore = new SemaphoreSlim(50, 50); 
List<Task> taskList = new List<Task>(); 

foreach (var item in collection) 
    { 
     await semaphore.WaitAsync(); 

     taskList.Add(
     Task.Run(() => 
     { 
      item.Property = DoTheThing(item.AnotherValue).Result; 
      db.SaveChanges(); 
      semaphore.Release(); 
     })); 
    } 

    await Task.WhenAll(taskList); 

仕組み:セマフォで

  1. を単純なwaitではなく、asyncモード
  2. WaitAsync
  3. セマフォは、forループが並ん停止したときに最後に、その後、WhenAllは、すべてのコールは/タスク、DBプロセスを行うことが保証されます彼らは
  4. を実行すると50回の呼び出しがタスクリストに進み、キューすることを可能にするUIスレッドをブロック解除し続けます続行する前に終了する
関連する問題