2017-04-11 6 views
2

私はC#でスレッディングを少し新しくしましたが、かなりのことをしているコードベースを継承しました。私は、論理的に連続して実行されているように見えるいくつかのマルチスレッドコードセグメントを見ています。アプリケーションをデバッグすることは、これは私もUIスレッドであると仮定し、メインスレッド上で実行されて明らかになった現在の同期コンテキストを使用する並列ForEach

// Draw the nodes. 
var factory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); 
var drawingTasks = new List<Task>(nodePoints.Count); 
Parallel.ForEach(nodePoints, nodePoint => 
{ 
    Task task = factory.StartNew(() => DrawNode(token, nodePoint, groupList), token, TaskCreationOptions.None, factory.Scheduler); 
    if (task != null) 
     drawingTasks.Add(task); 
}); 

await factory.ContinueWhenAll(drawingTasks.ToArray(), result => 
{ 
    _event.Publish(new MapNodesDrawnEvent()); 
}); 

:ここでは例です。新しいスレッドは現在の同期コンテキストを使用しているので、メインスレッドでこれらのタスクをすべて順番に実行するのではないのですか?もしそうなら、これには何か価値がありますか?

答えて

3
  1. List<Task>はスレッドセーフではありません、あなたは(あなたはそれがまだ安全ではありませんリストを事前にサイズのにもかかわらず)ロックせずにParallel.ForEach内で使用することはできません。
  2. あなたがやっているのは、TaskFactoryを使って新しいスレッドを起動するだけであれば、それを並行して行う理由はありません。 StartNewを呼び出すことは信じられないほど速いので、必要はありません。あなたは、そののSynchronizationContextのセットを持っていたスレッドから呼び出された場合TaskScheduler.FromCurrentSynchronizationContext()と呼ばれる呼び出し元のスレッドがParallel.ForEach
  3. の内部で使用される可能性がありますので
  4. Parallelクラスは、ワーカースレッドの1つとして、呼び出し元のスレッドを使用していますUIスレッドまたはSynchronizationContext.SetSynchronizationContext(というバックグラウンドスレッドが呼び出されると、そのスケジューラで開始されたタスクがUIスレッドから実行されます。

投稿されたコードがあなたに与えた唯一の事柄(問題1を修正した場合、それは無制限のバグだった)は、処理されるメッセージキューの最後に作業をキューイングすることになります。後で作業を延期したい場合は便利ですが、Dispatcher.BeginInvokeを使用する方がはるかに良い方法です。

関連する問題