■97588 / inTopicNo.6) |
Re[3]: パラレル処理での共通変数 |
□投稿者/ 魔界の仮面弁士 (3124回)-(2021/06/09(Wed) 10:33:10)
|
■No97587 (メタルスライム さん) に返信 > 当該プロジェクトは .NET 4.0 でつくています
現時点で、新規開発のために .NET Framework 4 を採用されることはお奨めしません。
現行バージョンの OS に .NET 4.0 をインストールすることはできませんし .NET 4.0 は 2016/01/12 にサポート期限が終了しているためです。 (現在でもサポートされているバージョンは 4.5.2 以上および 3.5SP1 のみ)
> これを期に.NETを4.0から4.6にあげたほうが良いのでしょうね。 4.6 がリリースされたのは 6 年前ですし、今となってはそれも古い部類ですね。
サーバー系 OS や Win10 LTSB/LTSC などのために、あえて古いバージョンを採用することもありますが、 現行バージョンの Windows 10 であれば、既定で 4.8 がインストールされた状態になっているはずです。
Visual Studio 2017 は 4.6.1 世代の開発環境ですが、Developer Pack の導入により、 それ以降のバージョンの .NET Framework 4.8 向けの開発にも利用できます。 https://dotnet.microsoft.com/download/dotnet-framework https://dot.net/
参考までに、対応する OS バージョン一覧を載せておきます。
.NET 3.5 … Win7/2008/2008R2 にプリインストール(それ以降の OS にも導入可能) .NET 4.0 … プリインストールされた OS は無い(XP〜Vista,2003〜2008R2に導入可能) .NET 4.5 … Win8/2012 にプリインストール(Vista/7,2008/2008R2に導入可能) .NET 4.5.1… Win8.1/2012R2 にプリインストール(Vista〜8,2008〜2012に導入可能) .NET 4.5.2… プリインストールされた OS は無い(Vista〜8.1,2008〜2012R2に導入可能) .NET 4.6 … Win10[1507] にプリインストール(Vista〜8.1,2008〜2012R2に導入可能) .NET 4.6.1… Win10[1511] にプリインストール(7〜8.1,10[1507],2008R2〜2012R2に導入可能) .NET 4.6.2… Win10[1607]/2016 にプリインストール(7,8.1,10[1507〜1511],2008R2〜2012R2に導入可能) .NET 4.7 … Win10[1703] にプリインストール(7,8.1,10[1607],2008R2〜2016に導入可能) .NET 4.7.1… Win10[1709] にプリインストール(7,8.1,10[1607〜1703],2008R2〜2016に導入可能) .NET 4.7.2… Win10[1803〜1809]/2019 にプリインストール(7,8.1,10[1607〜1709],2008R2〜2016に導入可能) .NET 4.8 … Win10[1903以降] にプリインストール(7,8.1,10[1607〜1809],2008R2〜2019に導入可能)
※ .NET 5.0 や .NET 6.0 Preview は、.NET Framework とは系図が異なるので省略。
> 結局のところ Parallel.For ではできない、が結論ということなのでしょうか
完了するまで長い時間がかかる処理を、UI スレッドから Parallel.For してはいけません。
Parallel は、「短い時間で終わる作業」が多数ある場合に、 それを、指定した数のスレッドで分担して処理させる機能です。
また、WebSurfer さんが示されているように、Parallel.For や .ForEach を呼び出した場合、 その呼び出し元は、作業完了まで同期的に待たされることになります。 これらの呼び出しは非同期処理ではありません。
画面(UI)をフリーズさせること無く、長時間にわたるパラレル処理を行うのであれば、 バックグラウンドスレッドで Parallel クラスを呼び出してみてください。
.NET Framework 4.5 以降であれば Async/Await を使う所ですが、 .NET Framework 2.0〜4.0 世代で非同期な作業をさせたいのであれば、 Form に BackgroundWorker を貼って使うのがお手軽かと思います。
> また共通の変数に値を代入したい件だけ実現しようと思えば > 下記のコードの考え方は正しい方法なのでしょうか
Parallel.For は並列処理ですが非同期処理ではありませんので、 サンプルとはいえ Sleep(1000) を呼ぶようなコードは本来望ましくありません。
また、SyncLock は比較的実行コストの高い操作となります。
自作クラスを用意するほどのものでもない軽量なコレクションの場合には、 SyncLock ではなく、スレッドセーフなコレクションやメソッドを使う方が望ましいです。 https://www.atmarkit.co.jp/ait/articles/1802/07/news019.html https://www.atmarkit.co.jp/ait/articles/0505/25/news113_3.html
SyncLock ステーメントを使うとしても、フォームから直接呼び出すのは事故の元です。 スレッドセーフではない読み書き処理のすべての箇所をロックせねばならないため、 うっかり SyncLock を書き忘れて変数を読み書きしてしまう事故が発生しやすいですし、 使いどころを間違えるとデッドロックの要因にもなりえるためです。
そのため SyncLock ステーメントを使うのであれば、呼び出し漏れがないように 読み書きする処理をプロパティやメソッドに入れて内部的に SyncLock し、 かつ、そのロックオブジェクトを「外部から操作できない Private なオブジェクト」を 指定することで、ロック漏れやデッドロックを防止します。 https://www.itmedia.co.jp/enterprise/articles/0503/23/news086_2.html
|
|