0

現在、マルチスレッド同期を試しています。バックラウンドには、約 100000 個のオブジェクトのセットがあります。おそらくそれ以上です。1 秒あたり複数回、さまざまな方法で処理したいと考えています。

今、私が最も懸念しているのは、同期のパフォーマンスです。

これは問題なく動作するはずだと思います(これは単なるテストプログラムであり、エラーが発生するとプログラムがクラッシュするため、セキュリティの側面はすべて省略しました..)。私は 2 つの関数を書きました。1 つ目はプログラムのメイン スレッドによって実行され、2 つ目はすべての追加スレッドによって実行されます。

void SharedWorker::Start()
{
    while (bRunning)
    {
        // Send the command to start task1
        SetEvent(hTask1Event);

        // Do task1 (on a subset of all objects) here

        // Wait for all workers to finish task1
        WaitForMultipleObjects(<NumberOfWorkers>, <ListOfTask1WorkerEvents>, TRUE, INFINITE);

        // Reset the command for task1
        ResetEvent(hTask1Event);

        // Send the command to start task2
        SetEvent(hTask2Event);

        // Do task2 (on a subset of all objects) here

        // Wait for all workers to finish task2
        WaitForMultipleObjects(<NumberOfWorkers>, <ListOfTask2WorkerEvents>, TRUE, INFINITE);

        // Reset the command for task2
        ResetEvent(hTask2Event);

        // Send the command to do cleanup
        SetEvent(hCleanupEvent);

        // Do some (on a subset of all objects) cleanup

        // Wait for all workers to finish cleanup
        WaitForMultipleObjects(<NumberOfWorkers>, <ListOfCleanupWorkerEvents>, TRUE, INFINITE);

        // Reset the command for cleanup
        ResetEvent(hCleanupEvent);
    }
}

DWORD WINAPI WorkerThreads(LPVOID lpParameter)
{
    while (bRunning)
    {
        WaitForSingleObject(hTask1Event, INFINITE);

        // Unset finished cleanup
        ResetEvent(hCleanedUp);

        // Do task1 (on a subset of all objects) here

        // Signal finished task1
        SetEvent(hTask1);

        WaitForSingleObject(hTask2Event, INFINITE);

        // Reset task1 event
        ResetEvent(hTask1);

        // Do task2 (on a subset of all objects) here

        // Signal finished task2
        SetEvent(hTask2);

        WaitForSingleObject(hCleanupEvent, INFINITE);

        // Reset update event
        ResetEvent(hTask2);

        // Do cleanup (on a subset of all objects) here

        // Signal finished cleanup
        SetEvent(hCleanedUp);
    }

    return 0;
}

私の要件を指摘するために、簡単な例を挙げます。上記の 100000 オブジェクトを取得し、それぞれ 12500 オブジェクトの 8 つのサブセットに分割し、8 つの論理コアを備えた最新のマルチコア プロセッサを使用するとします。関連する部分は時間です。すべてのタスクは約 8 ミリ秒で実行する必要があります。

私の質問は、分割処理によって時間を大幅に短縮できるか、それともイベントによる同期が高すぎるかということです。または、すべてのタスクをこの方法で実行する必要がある場合、より少ない労力または処理時間でスレッドを同期する別の方法がありますか?

4

1 に答える 1

0

1 つのオブジェクトの処理が高速な場合は、スレッド間で分割しないでください。Windows でのスレッド同期は、すべてのコンテキスト スイッチで 50 ミリ秒をはるかに超えます。この時間はシステムによって使用されるのではなく、システム上で他の何かが実行されている時間です。

ただし、すべてのオブジェクトの処理に約 8 ミリ秒かかる場合は、スレッドのプール全体で作業をスケジュールするポイントがあります。ただし、オブジェクトの処理は多少異なる場合があり、多数のワーカー スレッドが別の時点で作業を完了します。

より良いアプローチは、処理するオブジェクトを追加し、そこからオブジェクトを処理から取り出す同期オブジェクト キューを編成することです。さらに、単一のオブジェクトの処理は、スレッドのスケジューリング間隔よりもかなり低いため、それらをバッチで処理スレッドに入れるとよい (10 ~ 20 など)。プール内のワーカー スレッドの最適な数と、テストを使用したバッチの最適なサイズを見積もることができます。

したがって、擬似コードは次のようになります。

main_thread:
    init queue
    start workers

    set counter to 100000
    add 100000 objects to queue
    while (counter) wait();

worker_thread:
    while (!done)
        get up to 10 objects from queue
        process objects
        counter -= processed count
        if (counter == 0) notify done
于 2013-03-19T14:02:11.817 に答える