none
並列化数の上限を決めて並列処理する方法 RRS feed

  • 質問

  • 課題
    不定期に発生する処理を並列化数の上限を越えない範囲で並列処理するワークフローを設計したい。例えるなら汎用計算機のバッチキューみたいな振る舞いをイメージしています。ただし、今回はジョブ単位ではなくてスレッド単位の並列処理を前提にしています。

    質問1 上記のワークフローを記述するために有益なFCLがありますか?
    課題のワークフローは一般的と思います。簡潔に記述することができますか?もしFCLに部品が用意されているなら活用したいと思います。有用であれば.NET 4の新機能、WF、その他、を使っても構わないです。

    質問2 もし、数十行レベルで記述できるのであればソースコード例を示していただければありがたいです。

    要件・前提
    (1)各処理が参照するデータは独立していて、どのような順番で実行しても良い。
    (2)処理の並列化数の上限をN個に設定すると、その時点で待ちの処理が残っていれば、上限を越えない範囲で実行を開始する。
    (3)上限は動的に変更できる。Nを小さい値に変更した時に一時的に上限を超えることは許容する。

    質問の背景
    不定期で処理が発生するためParallel.ForEachループは使えなさそうです。かといって従来のThreadで制御するのも面倒そうです。適切なFCLを活用してエレガントに実装したいです。(便利な部品がきっとあるに違いないと思っています)


    C#開発者
    2010年9月2日 9:51

回答

  • “際限なくスレッドが増えてしまっては”困るから、スレッド数を制限したいというお考えですね。

    でしたら、それこそParallel、Taskでよいと思います。

    これらはスレッドプールからスレッドを取得して要求を実行していますので、スレッドプール内のスレッド数がそのまま上限になります。

    (上限を超えた要求は空きスレッドができるまで待ち行列に入ります)

    • 回答としてマーク MicroVAX 2010年10月28日 3:36
    2010年10月26日 1:08

すべての返信

  • Parallelの元になっているTaskクラス を使うのはどうでしょう?

    ただし、並列化数の上限を指定する理由がよくわかりませんでした。提案したTaskは上限を指定できなかった(というか上限がInt32.MaxValueかな)と思います。 タスクの並列化 (タスク並列ライブラリ) を参考にしてみてください。

    2010年9月2日 10:46
  • 質問に対して単純にはHongliangさんの提示されたドキュメントが答えだと思います。

    ただ、Taskクラスがどのようなアプローチで動作しているのか知ってもらい、並列化数の上限を指定する意味があるのか考え直すのもありかなと思い、先のドキュメントを提示しました。

    2010年9月2日 12:17
  • ご回答ありがとうございます。

    方向性としては.NET 4のParallel、Taskあたりから検討すれば良いのですね。

    上限数を指定する意図は、資源(例ではCOMポート)の上の管理を厳密に行うことを意図していました。下の例のような場合、スレッドがCOMポートを必要としているは設計者しか知らないので何らかの方法で上限を指示する必要があると考えました。


    コンピュータに3個のCOMポートが実装されています。各スレッドは空いているCOMポート探して1個のCOMポートを占有します。このような場合、同時並列処理の上限を3個と指定することで、COMポートが不足しないことが保証されます。ある時、3個のうち1個のCOMポートを別の用途に一時的に使いたくなりました。その時は上限を3個から2個に変更することで、スレッド終了後1個のCOMポートを空けることができました。別の用途での使用が終了したので、再び上限を3個に戻しました。


    C#開発者
    2010年9月3日 7:58
  • それは同時実行数とは別でリソース管理になるのではと思います。

    で、具体的にはSemaphoreクラス が使えます。

    2010年9月3日 8:04
  • ご回答ありがとうございます。

    資源の個数が数えられるような場合(例 FAXサーバーのCOMポート数)はセマフォが使えますね。資源の個数が数えられないような場合(例 CPUの使用率が80%を越えたらスレッドを開始しない)Hongliangさんが指摘してくださったリンク先ということですね。
    並列処理は資源を枯渇させないよう細心の注意が必要なので、ソースコードの書き換えは慎重にしようと考えています。


    C#開発者
    2010年9月8日 11:12
  • リソースの要因がある場合はセマフォを提案しましたが、最初に質問に戻りますが、リソースの要因がない場合に、並列化数を制限したい理由がわかりませんでした。
    もしゆっくり実行したいのならもっと直接的にwaitを入れるべきです。
    2010年9月9日 0:36
  • “際限なくスレッドが増えてしまっては”困るから、スレッド数を制限したいというお考えですね。

    でしたら、それこそParallel、Taskでよいと思います。

    これらはスレッドプールからスレッドを取得して要求を実行していますので、スレッドプール内のスレッド数がそのまま上限になります。

    (上限を超えた要求は空きスレッドができるまで待ち行列に入ります)

    • 回答としてマーク MicroVAX 2010年10月28日 3:36
    2010年10月26日 1:08