4

私はでC++アプリケーションを開発していますQt。私は非常に基本的な疑問を持っています、これがあまりにも愚かであるならば私を許してください...

最小時間でタスクをスレッド間で分割するには、いくつのスレッドを作成する必要がありますか?

私のラップトップは第3世代i5プロセッサ(3210m)であるため、これを求めています。つまり、デュアルコアであり、NO_OF_PROCESSORS 環境変数が4を示しています。アプリケーションのダイナミックメモリは、そのアプリケーションを起動したプロセッサでのみ使用できるという記事を読んだことがあります。それで、1つのスレッド(env変数は4プロセッサを言うので)または2つのスレッド(私のプロセッサはデュアルコアであり、env変数はコアの数を示唆している可能性があるため)または4つのスレッド(その記事が間違っていた場合)を作成する必要がありますか?私はQtを学ぼうとしている初心者レベルのプログラマーなので、ご容赦ください。ありがとうございました :)

4

4 に答える 4

4

ハイパースレッディングはやや嘘ですが(4つのコアがあると言われていますが、実際には2つのコアしかなく、別の2つは、前の2つが使用しないリソースでのみ実行されます)、正しいことは、指示された数のスレッドを使用するNO_OF_PROCESSORSことです。

Intelだけがあなたに嘘をついているわけではないことに注意してください。最近のAMDプロセッサでは、6つの「実際の」コアがありますが、実際には4つしかなく、リソースが共有されています。

ただし、ほとんどの場合、それは多かれ少なかれうまくいきます。スレッドを明示的にブロックしない場合でも(待機関数またはブロック読み取りで)、たとえばキャッシュミスが原因でメモリにアクセスする場合など、コアが停止するポイントが常にあります。これにより、ハイパースレッドコア。

したがって、やるべきことがたくさんあり、それをうまく並列化できる場合は、広告されたコアと同じ数のワーカーが実際に存在する必要があります(それらが「本物」であるか「ハイパー」であるかは関係ありません)。このようにして、利用可能なプロセッサリソースを最大限に活用します。

理想的には、アプリケーションの起動の早い段階でワーカースレッドを作成し、タスクをワーカーに渡すためのタスクキューを用意します。同期は無視できないことが多いため、タスクキューはかなり「粗い」必要があります。最大コア使用量と同期オーバーヘッドにはトレードオフがあります。

たとえば、処理する配列に1,000万の要素がある場合、100,000または200,000の連続する要素を参照するタスクをプッシュできます( 1,000万のタスクをプッシュする必要はありません!)。そうすることで、平均してアイドル状態のコアがないことを確認し(1つが早く終了した場合、何もしない代わりに別のタスクをプルします)、同期は100程度しかなく、そのオーバーヘッドはほぼ無視できます。

タスクにファイル/ソケットの読み取りなど、無期限にブロックされる可能性のあるものが含まれる場合、別の1〜2スレッドを生成することは間違いではないことがよくあります(少し実験が必要です)。

于 2013-01-26T16:44:47.780 に答える
2

これは完全にワークロードに依存します。CPUを集中的に使用するワークロードがある場合は、CPUのスレッド数(この場合は4、ハイパースレッディングの場合は2コア* 2)に近づける必要があります。スレッドの1つがロックなどを待機する時間を補うことができるため、わずかなオーバーサブスクリプションでも問題ない場合があります。
一方、アプリケーションがCPUに依存せず、ほとんど待機している場合は、CPU数よりも多くのスレッドを作成することもできます。ただし、スレッドの作成はかなりのオーバーヘッドになる可能性があることに注意してください。唯一の解決策は、ボトルネックがあったかどうかを測定し、その方向に最適化することです。

また、c ++ 11を使用している場合は、使用std::thread::hardware_concurrencyしているcpuコアの数を決定するための移植可能な方法を取得するために使用できることにも注意してください。

動的メモリに関する質問については、そこで何かを誤解している必要があります。通常、作成するすべてのスレッドは、アプリケーションで作成したメモリにアクセスできます。さらに、これはC ++とは関係がなく、C++標準の範囲外です。

于 2013-01-26T16:46:20.840 に答える
1

NO_OF_PROCESSORSCPUにハイパースレッディングがあるため、4が表示されます。ハイパースレッディングは、単一のコアが同じアプリケーションの2つのスレッドを多かれ少なかれ同時に実行できるようにする技術のIntel商標です。たとえば、一方のスレッドがデータをフェッチし、もう一方のスレッドがALUにアクセスしている限り機能します。両方が同じリソースを必要とし、命令を並べ替えることができない場合、1つのスレッドが停止します。これが、2つあるのに4つのコアが表示される理由です。

動的メモリが使用できるのはコアの1つだけですが、IMOは正しくありませんが、コンテンツを登録し、場合によってはコンテンツをキャッシュします。RAMにあるものはすべて、すべてのCPUで使用できる必要があります。

オペレーティングシステムのスケジューラーの動作やデータへのアクセス方法などに応じて、CPUよりも多くのスレッドが役立ちます。コードのベンチマークを行う必要があることを確認します。他のすべては単なる当て推量になります。

それとは別に、Qtを学ぼうとしているのであれば、これは心配するのが正しいことではないかもしれません...

編集:

あなたの質問に答える:スレッドの数を増やした場合にプログラムがどれだけ遅く/速く実行されるかを実際に伝えることはできません。あなたがしていることに応じて、これは変わります。たとえば、ネットワークからの応答を待っている場合は、スレッドの数をさらに増やすことができます。スレッドがすべて同じハードウェアを使用している場合、4つのスレッドは1よりもパフォーマンスが良くない可能性があります。最良の方法は、単にコードをベンチマークすることです。

理想的な世界では、4つまたは8つのスレッドを実行している場合、数値を計算しても違いはありません。正味の時間は同じである必要があります(コンテキストスイッチの時間を無視するなど)。応答時間は異なります。重要なのは、理想的なものは何もないということです。キャッシュがあり、CPUはすべて同じバスを介して同じメモリにアクセスするため、最終的にはリソースへのアクセスをめぐって競合します。次に、特定の時間にスレッド/プロセスをスケジュールする場合としない場合があるオペレーティングシステムもあります。

また、同期オーバーヘッドの説明を求めました。すべてのスレッドが同じデータ構造にアクセスする場合は、更新中に無効な状態のデータにスレッドがアクセスしないように、ロックなどを行う必要があります。

2つのスレッドがあり、どちらも同じことをしていると仮定します。

int sum = 0; // global variable

thread() {
    int i = sum;
    i += 1;
    sum = i;
}

これを同時に実行する2つのスレッドを開始すると、出力を確実に予測できなくなります。次のように発生する可能性があります。

THREAD A : i = sum; // i = 0
           i += 1;  // i = 1
**context switch**
THREAD B : i = sum; // i = 0
           i += 1;  // i = 1
           sum = i; // sum = 1
**context switch**
THREAD A : sum = i; // sum = 1

結局、スレッドを2回開始したとしても、ですsum。これを回避するには、共有データへのアクセスを同期する必要があります。通常、これを行うには、必要な限りへのアクセスをブロックします。同期オーバーヘッドは、リソースが再びロック解除されるまでスレッドが待機し、何もしない時間です。12sumsum

スレッドごとに個別の作業パッケージがあり、共有リソースがない場合は、同期のオーバーヘッドがないはずです。

于 2013-01-26T16:47:08.497 に答える
0

Qtでスレッド間で作業を分割することを開始する最も簡単な方法は、QtConcurrentフレームワークを使用することです。例:QList内のすべてのアイテムに対して実行する操作があります(かなり一般的です)。

void operation( ItemType & item )
{
  // do work on item, changing it in place
}

QList<ItemType> seq;  // populate your list

// apply operation to every member of seq
QFuture<void> future = QtConcurrent::map( seq, operation );
// if you want to wait until all operations are complete before you move on...
future.waitForFinished();

Qtはスレッドを自動的に処理します...それについて心配する必要はありません。QFutureのドキュメントではmap、必要に応じて、シグナルとスロットを使用して非対称に完了を処理する方法について説明しています。

于 2013-01-26T21:57:26.480 に答える