0

c# 3.0 でのマルチスレッドの最適なアプローチの提案が必要 (並列またはタスクなし)

状況は、500 アイテムのキューがあります。特定の時点では、10 スレッド (最大) しか実行できません。以下は私のコードです。

While (queue.Count > 0)
{
Thread[] threads = new Thread[no_of_threads];
for (int j = 0; j < no_of_threads; j++)
 {
   threads[j] = new Thread(StartProcessing);//StartProcessing Dequeue one item each time //for a single thread
   threads[j].Start();
 }

 foreach (Thread objThread in threads)
 {
   objThread.Join();
 }
}

このアプローチの問題は、たとえば、no_of_threads = 10 で、そのうちの 9 つのスレッドが処理を完了し、1 つのスレッドがまだ動作している場合、ループから抜け出せず、10 個のスレッドすべてが処理されるまで空きスレッドに作業を委譲できないことです。終わり。

キュー数が 0 を超えるまで、常に 10 個のスレッドが動作する必要があります。

4

5 に答える 5

4

これは、 Semaphoreを使用して簡単に実行できます。

アイデアは、最大数 N のセマフォを作成することです。ここで、N は許可するスレッドの数です。ループはセマフォで待機し、セマフォを取得するとタスクをキューに入れます。

Semaphore ThreadsAvailable = new Semaphore(10, 10);
while (Queue.Count > 0)
{
    ThreadsAvailable.WaitOne();
    // Must dequeue item here, otherwise you could run off the end of the queue
    ThreadPool.QueueUserWorkItem(DoStuff, Queue.Dequeue());
}

// Wait for remaining threads to finish
int threadCount = 10;
while (threadCount != 0)
{
    ThreadsAvailable.WaitOne();
    --threadCount;
}


void DoStuff(object item)
{
    ItemType theItem = (ItemType)item;
    // process the item
    StartProcessing(item);
    // And then release the semaphore so another thread can run
    ThreadsAvailable.Release();
}

アイテムはメイン ループでキューから取り出されます。これは、処理が面倒な競合状態を回避するためです。スレッドにアイテムをデキューさせる場合、スレッドはこれを行う必要があります。

lock (queue)
{
    if (queue.Count > 0)
        item = queue.Dequeue();
    else
        // There wasn't an item to dequeue
        return;
}

そうしないと、キューにアイテムが 1 つしか残っていないときに、次の一連のイベントが発生する可能性があります。

main loop checks Queue.Count, which returns 1
main loop calls QueueUserWorkItem
main loop checks Queue.Count again, which returns 1 because the thread hasn't started yet
new thread starts and dequeues an item
main loop tries to dequeue an item and throws an exception because queue.Count == 0

そのように物事を処理する気があるなら、あなたは大丈夫です。Release重要なのは、スレッドが終了する前にスレッドがセマフォで呼び出すことを確認することです。明示的に管理されたスレッド、またはThreadPool私が投稿したアプローチでそれを行うことができます。ThreadPoolスレッドを明示的に管理するよりも簡単だと思ったので、使用しました。

于 2013-05-06T17:01:32.727 に答える
1

ThreadPoolスレッドを管理および最適化するを使用する必要があります

プール内のスレッドがそのタスクを完了すると、スレッドは待機中のスレッドのキューに戻され、そこで再利用できます。この再利用により、アプリケーションはタスクごとに新しいスレッドを作成するコストを回避できます。

通常、スレッド プールには最大数のスレッドがあります。すべてのスレッドがビジー状態の場合、スレッドが使用可能になってサービスが提供されるまで、追加のタスクがキューに入れられます。

ThreadPoolスレッドの管理と割り当ては十分にスマートなので、干渉しない方がよいでしょう。ただし、本当にこれを行う必要がある場合は、SetMaxThreadsメソッドを使用して最大スレッド数の制約を設定できます

于 2013-05-06T16:32:06.960 に答える
0

これは単純な生産者と消費者のシナリオです。次のようなスレッド セーフなキューが必要です: .NET でブロッキング Queue<T> を作成しますか? - キューが空になるまで、10 個のスレッドがループ内のジョブごとにジョブを読み取り、処理できます。キューをどのように満たすか (処理を開始する前または処理中に) に応じて、キューが空になるとすぐに、または停止フラグを使用して停止するように信号を送ると、これらのスレッドを終了できます。後者の場合、おそらくスレッドを起こす必要があります (たとえば、ダミー ジョブを使用)。

于 2013-05-06T16:30:58.777 に答える
0

外部からスレッドを制御する代わりに、各スレッドがデータ自体を消費できるようにします。

擬似コード:

create 10 threads

thread code:
    while elements in queue
    get element from queue
    process element
于 2013-05-06T16:31:57.860 に答える