36

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

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

私は MSDN の例を調べて、それを私のニーズに合わせて調整しました。私が参照する例はここにあります: http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80,printer).aspx

私の問題はこれです。HttpWebRequestWebResponseクラスを介して Web ページをロードし、 を介して結果を読み取るかなり単純なコード セットがありますStream。このメソッドは何度も実行する必要があるため、スレッドで起動します。メソッド自体はかなり短いですが、(毎回さまざまなデータで) 起動する必要がある回数はさまざまです。1 から 200 までの任意の値を指定できます。

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

ビアに設定してみましMaxThreadsた:ThreadPool

ThreadPool.SetMaxThreads(3, 3);

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

MSDN の例では、イベント ドライブのアプローチと呼び出しWaitHandle.WaitAll(doneEvents);を使用しています。これが私が行っている方法です。

したがって、私の質問の核心は、コードで実行できるスレッドの最大数をどのように保証または指定するのですか?ただし、前のスレッドが任意の時点まで終了するときに、コードはより多くのスレッドを実行し続けますか? 私はこれに正しい方法で取り組んでいますか?

心から、

ジェイソン


さて、セマフォ アプローチを追加し、ThreadPoolコードを完全に削除しました。それは十分に単純に思えます。http://www.albahari.com/threading/part2.aspxから情報を入手しました。

方法を示したのは次の例です。

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

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

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

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();
        }
    }
}
4

2 に答える 2

32

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


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

この場合、セマフォを使用してリソースへのアクセスを管理します。あなたの場合、リソースはWebスクレイプを実行しているか、レポートを計算しています。

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

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 回デクリメントされると、いずれかのスレッドがカウンターをインクリメントするまで、すべてのスレッドがブロックされます。

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


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

一方、3 つのスレッド (作成したもので、スレッドプールにはありません) があり、キューから作業をポップして実行します。これはセットアップがそれほど難しいものではなく、非常に高速で簡単です。

例:

于 2009-01-14T21:06:46.610 に答える
0

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

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

于 2009-01-14T21:02:31.737 に答える