新年早々Parallel.ForEachを使ったマルチスレッド処理でドハマリ

2023年1月2日月曜日

C#.net/VB.net

t f B! P L
あけめしておめでとうございます。


結局年末はずっとお休み。体調自体は戻っていた物の…お外が寒い…
で、長期の連休時にいつも行うバッチ処理を今回も行うことに。
まぁ…バッチ処理といっても要するにファイルの整理なんですが。

で、今回はその処理を行う為のバッチを書いてる時にドハマリした話。

今回ドハマリしたのは「マルチスレッドの例外処理」。
画面上の一覧から対象を選択してそれぞれに対して定型作業を行う…のをマルチスレッドで行うという内容。

問題の箇所


ここで久しぶりに並列処理としてParallel.ForEach を使ったんですよ。

普段仕事ではそもそもマルチスレッド処理なんか必要にならないように設計するし、パラレル処理スル必要がある場合は対象の選別を外でやってexe自体を複数起動することにより、マルチスレッドにする事によるバグを避けますからね。
業務プログラムの場合、不都合は直接にお金や労働時間に反映されちゃいますから。

決して業務アプリ屋にはマルチスレッド処理をまともに書けるプログラマなんか禄にいないという切実な理由というわけではない。
いやだって即席でなんちゃってプログラマに仕立て上げられた、ifとforしか知らない新人が成長したところでそんなの書ける訳ないじゃ無いですか。そういう人達に取ってPGは食う手段であって興味なんかこれっぽっちも無いんだもん。
それにどっちかというと業務アプリ屋は仕様の矛盾とその穴から来る業務上の不都合を見つけられる事に特化しく傾向がありますからねぇ…

本来仕様の不都合に気がつかないといけない立場の上流の人達は「よきにはからへ」と言うだけで気がつく事を放棄してることが多いですしね。なんかしら仕様上の不都合が発生すると結局は何も出来ずにあたふたしてるだけですし。
で。仕様上の不都合発見して教えてあげると余計なこと言うなとか平気で言ってくるし、結局不都合により起ったデータの不備やら直すの丸投げしてくるんですよね。

実際に処理が書けるSEと、書けないSEでは仕様上の不都合発生率が天と地程違う。
マジで。



閑話休題…新年早々何書いてるんだ…

結論。

Parallel.ForEach(Parallel.For)の内部で例外発生すると処理途中の処理が終わったら何も言わずにループから抜ける

これ。
MSDNのParallel.ForEachの例外処理に関する記述
MSDNのParallel.ForEachの例外処理に関する記述
サイトはココ。

今回、原因に気がつくまでやたら時間がかかったのは
  • 開発は普段使いPC、処理自体はPCサーバと処理が分かれている
  • かつ、テストデータは用意していたものの、例外が発生するようなテストデータでは無かった。
  • 並列処理の内容はここ数年特に不都合無く動作している処理
事が主な原因。
なので、
  • 開発機では事象が発生せず完走する
  • 実機では不特定な位置で処理が途中で止まる。
    処理自体は出来ている様に見えてしまう。
  • イベントビューアには何も出ない
という、なんだコレ?な事象に頭を悩ませたというワケ。
スレッド分かれているので途中でスレッド間で変数が混ざった・スレッドセーフな型を使っていない・対象となる母数が途中で変わっちゃった等、いろいろ原因考えましたが…

結局は「想定外の箇所で例外が発生していた」のが根本原因。
で、「Parallel.ForEach中の例外が発生したときの挙動」がまた特異だった。

Parallel.ForEach中に例外が発生すると、要するに
  • 例外発生したスレッドは終了する
  • それ以外の動いてるスレッドは最後まで走ろうとする
  • 発生した時点の並列実行中の処理が一段落したらループから抜ける
ってのを何も通知せずに行ってくれる。

いやそれイベントビューアに出すか、
せめて落ちたよって通知を一言ぐらい出せよと…

デバッグ中に発生する通知
デバッグ中に発生する通知

全体をtry-catchで囲んでなかったウチが悪いんですけどね…

元旦の夜から半日ほど悩みました。

そして現在
処理ぶん回し中

うーん…これは正月にやることか?


人気の投稿

このブログを検索

ブログ アーカイブ

QooQ