■55229 / inTopicNo.7) |
Re[4]: Parallel.For と Invoke メソッドの使い方 |
□投稿者/ kait (3回)-(2010/11/22(Mon) 22:46:54)
|
shu さん、なちゃさん、Azulean さん、ありがとうございます。
> 再現させてみましたが、Invoke メソッドで止まっているようですね。
> あまりに呼びすぎてあふれたんだろうか。
>
> 個人的にはこれの原因を突き止めるよりは、「そんなに呼ばないこと」で
> 済ませておいた方が良いような気はします。
> 時間をかける割にはきちんとした見解にまとまらない可能性があるので。
そ…そうですか(´Д`;)
実は元々のプログラムはもっと複雑でして、徐々に問題を単純化していったところ、
このあたりが問題だということがわかったというものです。
元々のプログラムでは、数百個のデータ配列があり、
このそれぞれのデータを Parallel.For のマルチスレッドで処理し、
進捗状況をプログレスバーとラベルで表示しようとしていました。
しかし何度やっても処理が終わらず、固まる場所もいろいろで…。
普通、このような処理は Parallel.For でおこなわない、というより、
マルチスレッドでおこなわないものなのでしょうか…?
よくあるシナリオのような気がしますが…。
…と悩んでいたところ、ヘルプにこのような記述を見つけました。
データとタスクの並列化における注意点
http://msdn.microsoft.com/ja-jp/library/dd997392.aspx
この中の、「UI スレッドでの並列ループの実行は避ける」に以下の記述があります。
> UI スレッドで並列ループを実行する場合は、そのループ内から UI コントロールを
> 更新しないように注意する必要があります。UI スレッドで実行されている
> 並列ループ内から UI コントロールを更新しようとすると、UI 更新の呼び出し方法に
> よっては、状態の破損、例外、更新の遅れ、さらにはデッドロックが発生する場合があります。
(´Д`;)なんてこったい…。まさにこのデッドロックの状態だったわけですね…。
さらに下にコード例が載っていますが、Parallel.For ループを、
ひとつのワーカースレッド内で実行するように記述すればよいようです。
コード例と同様に Task.Factory.StartNew メソッドで Parallel.For ループをくくったところ、
途中で停止するということはなくなりました!!
具体的には、
System.Threading.Tasks.Parallel.For(0, 100, n =>
{
Invoke(new MethodInvoker(A));
});
を、
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
System.Threading.Tasks.Parallel.For(0, 100, n =>
{
Invoke(new MethodInvoker(A));
});
});
に変更しました。
しかし Task.Factory.StartNew でくくってしまうと、そのスレッドの待ち合わせを
手動で記述しなければならないのですが、それはまた考えます。
マルチスレッドの難しいところは、コンパイルができたからといっても、
〜してはならない、という作法が多数あり、安心できない点ですよね。
ここで解決とさせていただきたいと思います。
みなさまのヒントのおかげです。ありがとうございました。
|
解決済み
|