Morning Girl

Web API, Windows, C#, .NET, Dynamics 365/CRM etc..

【C#】TPL:Parallelによる並列処理

前回Dynamics CRM のExecuteMultipleRequestによる一括処理を調べて、この次は並列処理かな! と思ったのですが、 そもそもDynamics CRMで並列処理、という前に、並列処理そのものの理解を深めないといけないな、ということで。

.NET Frameworksによる並列処理

.NET Frameworksでは、並列処理の方法が色々あるみたいです。 バージョンが上がるに従って、いろいろと増えていっているみたいですが、

というか、まず前提として非同期と並列の違いって何よ、というところから始まったので、ちょっと調べました。

一番詳しく、かつ自分の求めていた答えに近かったのは、以下のサイトです。

■非同期処理の種類

非同期処理の種類 (C# によるプログラミング入門)

自分の理解として、以下記載していこうと思います。

非同期処理と並列処理

そもそも根幹として、非同期処理というものがベースにあり、その用途やシナリオによって

・非同期処理

 -バックグラウンド処理

 -並列処理

と別れる感じです。

バックグラウンド処理が、主にGUIで使われるイメージが強い。 ボタンを押して、何かの処理を実施した際、バックグラウンドで処理が走っているイメージ。UIスレッドとは別スレッドで処理が行われている感じです。

それに対して並列処理は、上記URLの概要にもある通り、マルチコアCPUの性能を最大限に活かすため、並行した処理を実施するもの。

前者はasync、await、後者はParallel.for、eachになるのかな、と。

でも、そもそもの根幹はSystem.Threadingでどちらも同じ、と。

Parallel

で、今回私が求める要素としては、並列処理、Parallel.forなのだなぁと改めて理解したところで、実際にシンプルなParallelを使ってみたいと思います。

ちなみにParallelクラスは大きく分けて3種類のStaticクラスを提供しており 【Parallel.For】 【Parallel.ForEach】 【Parallel.Invoke】 の3種類になります。

MSDN Parallel クラス

Parallel クラス (System.Threading.Tasks)

それぞれ、For、ForEachは元来のものとあまり変わりません。

今回試したParallel.Forであれば、第1引数に初期値、第2引数に上限値、後述するオプション、第4引数に実際の処理内容をラムダ式などで記載する形になります。

ここで1つ重要になるのが、第3引数のオプションです。 ParallelOptionsクラスを渡すところなのですが、Parallelは上限値のスレッドを決めない限り、自動的にスレッドをどんどん生成していきます。

このページがかなり詳しく、丁寧に解説しています。

非同期I/O待ちcsharptan.wordpress.com

各スレッドの処理が休止状態に入ると、CPUのリソースを有効活用するためか、どんどんスレッドを生成していきます。 試しに、Dynamics CRMの組織サービス接続で、ParallelForを実行したところ、120ほどスレッドが生成されてしまいました。

もちろん、並列処理時、クライアントからサーバーに処理を投げて、返答待ちみたいな状態であれば、スレッドをある程度作ったほうが効果的な側面もあるかもしれませんが、ある程度の数値をParallelOptionsで指定したほうが良さげです。

以下、試しにParallel.Forを書いてみました。

using System;
using System.Threading.Tasks;

namespace MyProject.ParallelFor
{
    class Program
    {
        static void Main(string[] args)
        {
            // ParallelOptionsで2スレッドまでに制限
            ParallelOptions option = new ParallelOptions();
            option.MaxDegreeOfParallelism = 2;

            Parallel.For(0, 100, option, i =>
            {
                Console.Write(i + ",");
            });

            Console.ReadKey();
        }
    }
}

処理結果

Console.Writeの記述結果が、順次ではなくバラバラになっており、並列処理が行われたことがわかります。

f:id:sugimomoto:20150409133825p:plain

ほんの一端ですが、並列処理の1つに触ることができました。

今後もちょいちょいTaskやawait,asyncなど触って行きたいところです。