c++ - 終了 - ワーカースレッド とは




スレッドの作成と終了はWindowsでどのくらいかかるのですか? (2)

複雑な配列処理タスクを複数のスレッドに分割してマルチコア処理を利用し、大きなメリットを見ています。 現在、タスクの開始時にスレッドを作成し、作業を完了すると終了するのを待ちます。 私は通常、各スレッドが異なる時間量を取る可能性があり、余分なスレッドを持つことによって、すべてのコアがほとんどの時間占有されていることを保証するので、コアの数の約4倍のスレッドを作成しています。 私は、プログラムが起動するときにスレッドを作成し、必要になるまでアイドル状態にしておき、処理を開始するときにスレッドを使用することで、パフォーマンスの利点がたくさんあると思っていました。 もっと簡単に言えば、スレッド内の処理を超えて新しいスレッドを開始したり終了したりするのにどれくらい時間がかかりますか? 私は現在スレッドを使用して開始しています

CWinThread *pMyThread = AfxBeginThread(CMyThreadFunc,&MyData,THREAD_PRIORITY_NORMAL);

通常、私は64ビットアーキテクチャで8つのコアに32スレッドを使用します。 問題のプロセスは現在、1秒未満で完了し、ディスプレイがリフレッシュされるたびに起動されます。 スレッドの開始と終了が<1ms未満の場合、戻り値はその努力を正当化しません。 私はこれをプロファイリングするのにいくつかの難しさがあります。

ここで関連する質問は役に立ちますが、私が後にしていることについて少し曖昧です。 フィードバックは高く評価されます。


いくつかのアドバイス:

  1. 処理する作業項目がたくさんある場合(またはあまり多くはないが、時間全体の処理を繰り返す必要がある場合)、ある種のスレッドプールを使用していることを確認してください。 この方法では、スレッドを常に再作成する必要はなく、オリジナルの質問はこれ以上重要ではありません。スレッドは1回だけ作成されます。 私はQueueUserWorkItem APIを直接使用しています(私のアプリケーションはMFCを使用していないので)、あまりにも苦痛ではありません。 しかし、MFCでは、スレッドプーリングを利用するためのより高いレベルの機能を持つことができます。 ( http://support.microsoft.com/kb/197728
  2. 1つの作業項目に最適な作業量を選択してください。 もちろん、これはあなたのソフトウェアの機能に依存します:リアルタイムでなければならないのですか、それともバックグラウンドで数えられるのでしょうか? リアルタイムでない場合は、作業項目あたりの作業量が少なすぎると、スレッド間の作業分散のオーバーヘッドの割合を増やすことで、パフォーマンスが低下する可能性があります。
  3. ハードウェア構成は非常に異なる可能性があるため、エンドユーザーがさまざまなマシンを使用できる場合、ソフトウェアの起動時にいくつかの較正ルーチンを非同期に組み込むことができます。 較正の結果は、後で実際の計算のためのより良いワークサイズ設定のための入力となり得る。

私はかなり前に、同じ基本的な質問をしたときに書きました。 スレッドを作成するのにかかる時間だけでなく、スレッドが実行を開始するまでにどれくらい時間がかかるかを少し詳しく表示するように更新しました。

#include <windows.h>
#include <iostream>
#include <time.h>
#include <vector>

const int num_threads = 32;

const int switches_per_thread = 100000;

DWORD __stdcall ThreadProc(void *start) {
    QueryPerformanceCounter((LARGE_INTEGER *) start);
    for (int i=0;i<switches_per_thread; i++)
        Sleep(0);
    return 0;
}

int main(void) {
    HANDLE threads[num_threads];
    DWORD junk;

    std::vector<LARGE_INTEGER> start_times(num_threads);

    LARGE_INTEGER l;
    QueryPerformanceCounter(&l);

    clock_t create_start = clock();
    for (int i=0;i<num_threads; i++)
        threads[i] = CreateThread(NULL, 
                            0, 
                            ThreadProc, 
                            (void *)&start_times[i], 
                            0, 
                            &junk);
    clock_t create_end = clock();

    clock_t wait_start = clock();
    WaitForMultipleObjects(num_threads, threads, TRUE, INFINITE);
    clock_t wait_end = clock();

    double create_millis = 1000.0 * (create_end - create_start) / CLOCKS_PER_SEC / num_threads;
    std::cout << "Milliseconds to create thread: " << create_millis << "\n";
    double wait_clocks = (wait_end - wait_start);
    double switches = switches_per_thread*num_threads;
    double us_per_switch = wait_clocks/CLOCKS_PER_SEC*1000000/switches;
    std::cout << "Microseconds per thread switch: " << us_per_switch;

    LARGE_INTEGER f;
    QueryPerformanceFrequency(&f);

    for (auto s : start_times) 
        std::cout << 1000.0 * (s.QuadPart - l.QuadPart) / f.QuadPart <<" ms\n";

    return 0;
}

サンプル結果:

Milliseconds to create thread: 0.015625
Microseconds per thread switch: 0.0479687

最初のいくつかのスレッドの開始時刻は次のようになります。

0.0632517 ms
0.117348 ms
0.143703 ms
0.18282 ms
0.209174 ms
0.232478 ms
0.263826 ms
0.315149 ms
0.324026 ms
0.331516 ms
0.3956 ms
0.408639 ms
0.4214 ms

これらは単調に増加していますが、それ保証されていません(ただし、その一般的な方向には明確な傾向があります)。

最初にこれを書いたとき、私が使用したユニットはもっと意味がありました - 33 MHz 486では、そのような結果はこのような小さな分数ではありませんでした。 :-)いつか私が野心的だと思うと思うが、タイミングを行うためにstd::asyncを使ってスレッドとstd::chronoを作るためにこれを書き直すべきだが...







performance