Open3

vb.net 非同期平行処理のメモ

Kouta WakamatsuKouta Wakamatsu

やりたいこと

vb.netのwindowsフォームアプリケーションで時間のかかる処理の並列処理化

元々

DBから処理対象の抽出(3万件くらい)→対象一人一人に対応したとあるデータの抽出(For文)
データの抽出は、PG上の処理とDBへの問い合わせをいくらか繰り返し、加工したデータをテーブルへinsertしていく
2~10秒程I/O待ちのあるクエリが一つあるので、3万件相手に直列で行うと処理時間がとても長い

Kouta WakamatsuKouta Wakamatsu

並列処理&非同期にしてみた
Parallelで簡単にできそうだったので。。

Dim targetList as List(Of T)
Await Task.Run(Sub()
                   Dim result_cnt As Integer = 0
                   Parallel.ForEach(targetList ,
                                    Sub(行, loopState)
                                        Try
                                            Recommend(行)
                                        Catch ex As Exception
                                            LogTxtBoxAppend($"抽出処理例外:{ex.GetType().Name}({ex.Message})", True)
                                        End Try
                                        SyncLock Thread.CurrentContext
                                            result_cnt += 1
                                        End SyncLock
                                        Invoke(New DeleChangeText(AddressOf changeText), result_cnt)
                                    End Sub)
               End Sub)

おおむねこんな感じ
Recommend()の中でなんやかんややってる

サーバー構成がAWSでAPサーバとDBサーバにわかれていて、テスト環境で実行するとAPサーバーのCPU負荷は大したことないが、DBサーバのCPU負荷が100%で振り切って、しばらくするとsqlの実行タイムアウトが大量にかえってきた。。。

調べるとどうやら↓
https://csharptan.wordpress.com/2011/12/10/非同期io待ち/
こういうことらしい
非常に参考になった。
そこで、この記事にあるTask.WaitAllとExecuteReaderAsyncを使えばいけるかな?とおもったがRecommendの中でI/O待ちが長いExecuteReaderの処理があってこれを非同期にしたところで、I/O待ちのキューが結局多くなってDBサーバが悲鳴をあげるだけだという結論に至ったので、、(実際に検証してないのでわかりません)

https://kageura.hatenadiary.jp/entry/2015/04/10/190000
こちらを参考にParallel.Foreachのスレッド上限値を指定することにしました。
とりあえず、テストは4プロセッサなので上限4でやってみたところいい感じに処理がすすんだ。
試しに10に設定したところ、ギリギリ大丈夫なCPU負荷だったのでそもそもキュー数とDBサーバのプロセッサ数は同列に考えるべきではなさそう、たぶん

本番は36プロセッサあるし、処理速度も段違いなので少しずつあげて調整していきたいと思う。