web-dev-qa-db-ja.com

C#スレッドプール制限スレッド

わかりました...私はサイトに公正な検索を与え、このトピックに関する多くの投稿を読みました。私はこの質問を見つけました: C#の単純なスレッドプールのコード は特に役立ちます。

ただし、いつものように、必要なものは少し異なります。

私はMSDNの例を調べ、それを自分のニーズにいくらか適合させました。私が参照する例はここにあります: http://msdn.Microsoft.com/en-us/library/3dasc8as(VS.80、printer).aspx

私の問題はこれです。 HttpWebRequestおよびWebResponseクラスを介してWebページをロードし、Streamを介して結果を読み取る、かなり単純なコードセットがあります。このメソッドは、何度も実行する必要があるため、スレッドで起動します。メソッド自体は非常に短いですが、(毎回異なるデータで)起動する必要がある回数は異なります。 1〜200の範囲で指定できます。

私が読んだことはすべて、ThreadPoolクラスが最有力候補であることを示しているようです。ここでは、注意が必要なことを説明します。このことを100回実行する必要があるかもしれませんが、(この特定のタスクに対して)実行できるスレッドは最大で3つだけです。

MaxThreadsThreadPoolを設定してみました:

_ThreadPool.SetMaxThreads(3, 3);
_

このアプローチが機能していると私は完全には確信していません。さらに、これが実行されるシステムで実行されている他のWebサイトやプログラムを破壊したくありません。したがって、ThreadPoolのスレッド数を制限することで、これが自分のコードとスレッドにのみ関係することを確信できますか?

MSDNの例では、イベント駆動アプローチを使用し、WaitHandle.WaitAll(doneEvents);を呼び出します。これが私がこれを行う方法です。

だから私の質問の核心は、コードに対して実行できるスレッドの最大数をどのように確保または指定するかですが、以前のスレッドが任意のポイントまで完了すると、コードはより多くのスレッドを実行し続けるのでしょうか?私はこれに正しい方法で取り組んでいますか?

今後ともよろしくお願いいたします。

ジェイソン


さて、セマフォアプローチを追加し、ThreadPoolコードを完全に削除しました。シンプルなようです。私はから情報を得ました http://www.albahari.com/threading/part2.aspx

この例から、次のことがわかりました。

[下のテキストは、サイトからのコピー/貼り付けです]

容量が1のSemaphoreMutexまたはlockに似ていますが、Semaphoreに「所有者」がいない点が異なり、スレッドに依存しません。どのスレッドもReleaseSemaphoreを呼び出すことができますが、Mutexおよびlockを使用すると、リソースを取得したスレッドだけがリソースを解放できます。

この次の例では、10個のスレッドが途中でSleepステートメントを使用してループを実行します。 Semaphoreは、そのSleepステートメントを一度に実行できるスレッドが3つ以下であることを保証します。

_class SemaphoreTest
{
    static Semaphore s = new Semaphore(3, 3);  // Available=3; Capacity=3

    static void Main()
    {
        for (int i = 0; i < 10; i++)
            new Thread(Go).Start();
    }

    static void Go()
    {
        while (true)
        {
            s.WaitOne();

            Thread.Sleep(100);   // Only 3 threads can get here at once

            s.Release();
        }
    }
}
_
36
jason baisden

注:アプリを実行しているマシンを圧倒しないように、これを「3」に制限する場合は、まずこれが問題であることを確認します。スレッドプールはあなたのためにこれを管理することになっています。一方、他のリソースを圧倒したくない場合は、次に進んでください。


スレッドプールのサイズを管理することはできません(またはそれについてのほとんどすべてのことを管理できません)。

この場合、セマフォを使用してリソースへのアクセスを管理します。あなたの場合、あなたのリソースはウェブスクレイピングを実行している、またはいくつかのレポートを計算している、などです。

これを行うには、静的クラスでセマフォオブジェクトを作成します。

System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3);

次に、各スレッドで次のようにします。

System.Threading.Semaphore S = new System.Threading.Semaphore(3, 3);

try
{
    // wait your turn (decrement)
    S.WaitOne();
    // do your thing
}

finally {
    // release so others can go (increment)
    S.Release();
}

各スレッドは、続行するシグナルが与えられるまでS.WaitOne()でブロックします。 Sが3回デクリメントされると、それらの1つがカウンターをインクリメントするまで、すべてのスレッドがブロックされます。

このソリューションは完璧ではありません。


もう少しクリーンで効率的なものが必要な場合は、実行する作業をグローバルブロッキングキューオブジェクトにエンキューするBlockingQueueアプローチを使用することをお勧めします。

その間、3つのスレッド(スレッドプールではなく作成したスレッド)があり、実行するキューから作業をポップします。これはセットアップがそれほど難しくなく、非常に高速でシンプルです。

例:

30
Michael Haren

これは他のクラスと同様に静的クラスです。つまり、このクラスを使用すると、現在のプロセスの他のすべてのスレッドに影響します。他のプロセスには影響しません。

ただし、これは.NETの大きな設計上の欠陥の1つと考えています。誰がスレッドプールを作成するという素晴らしいアイデアを思いついたのでしょうか静的?あなたの例が示すように、システムの他の場所にある無関係なタスクに干渉することなく、ourタスク専用のスレッドプールが必要になることがよくあります。

0
jalf