マルチスレッドプログラミング相談室 その9
すいません質問します。
Matlobで、
例えば5000×5000の行列をAとして
その10×10の区分行列をBとします。
Aの対角線上にあるBだけを取り出して他が0行列の行列を作るにはどうすればいいですか?
また、各Bの対角要素だけ取り出すにはどうすればいいですか?
・とりあえず全てのパラメータから0を1つずつ取り除く
・Aは500×500の行列
・Bはたった1つの要素で、インデックスは i = j
それが500個ある
・つまり、「i==jであれば取り出す」それ以外は0にする。
・では、それを10倍したら?「 i ÷ 10 == j ÷ 10 」であれば、
取り出す(但し余りは全て切り捨てる)それ以外は全て 0
・但し i jの上限はインデックスが0からとして、4999までとする。
・俺はMatlabは使ったことが無いので具体的な実装は知らない。
・その次
・i と jの上限は 4999
・対角の部分行列は簡単、「i == jならば」取り出す。
・その右は、「i == j + 10 」も該当
・同様に、「i == j + 20, 30 ... 10*n ... 10*499」も該当
・同様に、「 i + 10 == 」も該当
・「i + 20, 30 ... 10*n ... 10*499 == j 」も該当
・「該当しなかったもの」はその都度0を代入する
【OS】OSX 10.8.5、Core i5
【言語】 C, C++
【実行環境】 XCode5.1, pthread
pthread を使って for ループを分割して実行するプログラムを書いたのですが、直列処理の方が速いです。
tbbやOpenMP でもやってみたのですが、直列の方が速いです。
上記の環境ではマルチスレッドで効率化を図るには、何か設定が必要なのでしょうか。
ざっくりした質問ですがヒントになるようなことでも教えて下さい。
>>391 プログラムを見ないと分からない。
マカーじゃないから見ても分からないかもしれないけど。
大前提として、マルチスレッド化して速くなるようなジョブなんだよね?
スレッドを作るのもjoinするのもスイッチするのも時間が掛かるので、
それらがペイしないと意味がない。
ちゃんと作っていて遅いのなら、キャッシュの競合の可能性があるかも
tbbのくっそ初心者です。
下記のコードを試したのですが、直列実行した方が速かったです。
これってそもそも並列化しても速くならない類の処理なのでしょうか?
int main( int argc, const char * argv[] ) {
tbb::task_scheduler_init init( 4 ); // 物理2スレ、論理4スレ core i5
PrimeCounter counter;
tbb::parallel_reduce( tbb::blocked_range< int >( 0, count__, count__ / 4 ), counter, tbb::simple_partitioner() );
}
他所のヘッダにて、
bool isPrime( int n ) { // この処理がアホみたいなのはわざとです
if ( n < 2 ) return false;
if ( n == 2 ) return true;
for ( int j = 3; j < n; ++j ) { if ( n % j == 0 ) { return false; } }
return true;
}
class PrimeCounter {
public:
int count;
PrimeCounter() : count( 0 ) {}
PrimeCounter( const PrimeCounter& instance, tbb::split ) : count( 0 ) {}
void operator() ( const tbb::blocked_range< int >& range ) {
for ( int i = range.begin(), end = range.end(); i < end; ++I ) {
if ( isPrime( i ) ) { ++count; } }
}
void join( const PrimeCounter& pc ) { count += pc.count; }
};
度々すみません、タイポありました。(多分本筋と関係ないですが)
関数 bool isPrime( int n ) のループ。
誤 for ( int j = 3; j < n; ++j )
正 for ( int j = 2; j < n; ++j )
RelativisticProgrammingを日本語で解説してるとこ、ないかな?
#include <stddef.h>
offsetof(type, member-designator);
僕の知り合いの知り合いができたパソコン一台でお金持ちになれるやり方
役に立つかもしれません
グーグルで検索するといいかも『ネットで稼ぐ方法 モニアレフヌノ』
4DXJZ
>>394 超亀レスだしテキトーだけど、counterがシングルトンなら
countのインクリメントでシリアライズされるんじゃね?
Intelのハイパースレッドでスケールするか否かのアルゴやデータ構造のパターンとか、評価基準をまとめた本なりサイトなり御存じでしたら教えてください。
400MBのデータを一括でコピーする処理を並列化してもノイマンボトルネックに掛かってスケールしないと思うんですが、boolの配列(newしたもの)でやるとある程度スケールします。
何でですか?
>>404 bool の配列が、例えば、8個の bool 値をまとめて 1バイトとして格納している場合で、
for ( i =0; i < 100000; i++ ) {
dst[i] = src[i];
}
のように書いて、かつ、コンパイラがこのループを「そこまでの」最適化はしなかった場合、
32BIT 環境の場合なら、32回のループで 1 DWORD 分の実メモリやキャッシュ・メモリへの
転送が生じるだけになるかも知れない。その他のメモリアクセスは、基本、code の
fetch だけになり、全てCPU内部のキャッシュ・メモリに乗ってしまう。
だから、マルチスレッドでこのループを分割して行えば、32スレッドまでなら、
高速化が起きる気がする。
そういう問題でなくて?
>>404 あ、あと
>400MBのデータを一括でコピーする処理を並列化してもノイマンボトルネックに
>掛かってスケールしないと思う
これだけど、以外に高速化されたりするかもしれない。
実際の CPUはそんなに賢くないので。
色々複雑。
チップセットや DDR DRAM、バス・アービタなどの事はそんなに詳しくは無いけど、
「ブロック転送命令」みたいなのがあるかも知れない。そして、
CPU で、rep movsd などが実行されるとき、CPU は、自分で転送せずに
チップセットと連携してバス・アービタにその命令を発行し、すぐに次の命令
から実行を再開したりするかも知れない。昔で言う「バスマスタ転送」や「DMA転送」
に似たようなやり方。
なんでそう思うかというと、主記憶(外部メモリ)はCPUのクロック速度にはついていけない
はずなのに、以外に CPU のブロック転送が速い気がするから。
確認は取ってない。
返信ありがとう。
DMA転送できるものをコンパイラが探知できるか疑問に思ってました。CPU機能としてのブロック転送は関係ありそうですね。
ワード単位処理は確かにやってそうです。
マルチコアでスケールできる処理って割りと限られてますね(汗。
>>408 [追加]
DMAでなくとも、CPU自身が命令実行の処理とは独立して主記憶の間で
転送をする仕組みは当然あるので、ブロック転送の予約みたいな事で、
実際の転送処理が終わってなくても次の命令に進んだりするようなことは
あるかも知れないと想像してみる。
無いかもしれないけど。
>>409 いや。例えば、バイナリだと、
rep movsd
の1命令がそこにあるだけで、命令表を見ればブロック転送をする命令とあって、
擬似命令レベルでの処理までは書かれているが、バス転送レベルでそれをCPUが
どう処理してるかまでは分からない。
double 1GBをコピー元のデータを加工してからコピーする場合は、どうやってもスケールしないんですかね、この話の感じからして。
書き込みタイミングが結果論でずらせるので、並列化で多少は見込みアルのかな。ーー自分で実験した方が良いですね。
>>412
1. 「加工」が単純に N 個に分割して処理できるものなら、N core の CPU の場合は、
大体 N 倍高速化できる可能性がある。
2. 加工の処理を大体同じ時間がかかる N 回のステージに分割できる場合、1つずつの
ステージを別々のCore で処理すれば、上手くすれば、大体 N 倍高速化できる。
ステージ 1 の出力をステージ2の入力にして、ステージ2の出力をステージ3の
入力にして・・・、という具合にするが、N が十分大きければ、高速化できる。
CPU 内部のスーパー・パイプラインも同じ考え方で、1つの命令をなるべく
たくさんのステージに分割することで、1つずつのステージの処理自体は軽く
されている。処理が軽ければロジックの入力から出力結果が出るまでの時間が
短く出来るのでクロック数を上げることができる。これと同じことが、ソフトウェア
の世界でも成り立つ。。
3. コピーの処理が完全に終わるのを待つ必要が無いなら、コピーを Sub Core で行えば、
Main Core は、待ち時間 0 で次の命令の実行に移れる。コピー後のデータを読み取る
必要が出てきた場所で初めて、同期オブジェクトの WaitForSingleObject()、
SetEvent() などで Main Core が Sub Core の処理が終わるまで待機すれば良い。 キャッシュにデータを書き込むけどメモリに書き込まない、とか
キャッシュのデータをメモリに書き込む動作をC++など言語で実装できないでしょうか。
勘でやる他ないのでしょうか。
>>414 自分で inline アセンブラか、単体のアセンブラを使えば出来る。
ただし、VC++ の inline アセンブラを使う場合は、結局、どんなコード
になるか分からない部分があるので、アセンブリ・ソース出力オプションか、
または、IDE の逆アセンブラでコードを確認する必要があると思うが。
ただ、個人的には、それ以上に、IA32のキャッシュ制御命令は、大量の
文書を読んで理解するのが大変に思うけれど。
>>414 intelの大体i5以上の新しい石だと
_xbegin _xend 等の1次キャッシュから下位のメモリへの
ストアタイミングをコントロールできるTSX命令群がそれっぽいかと思う
確か、もっと古いCPUでも、
mfence や、movxxxxx 系の命令でも色々出来たと思う。
物凄い複雑なので、ちゃんと理解してないけど。
以下のようなものも関係している。複雑すぎて理解してない。
https://xem.github.io/minix86/manual/intel-x86-and-64-manual-vol3/o_fe12b1e2a880e0ce-429.html ・WBINVD, PREFETCHh, CLFLUSH, CLFLUSHOPT,
・非一時的な移動命令(MOVNTI, MOVNTQ, MOVNTDQ, MOVNTPS,
MOVNTPD, INVD)
・第3レベルのキャッシュ無効化フラグ(IA32_MISC_ENABLE MSRのビット6)
質問:
ある資源を生成破棄するメーカースレッドがひとつと、その資源を使うユーザースレッドが複数ある。
メーカースレッドとユーザースレッドは排他的に資源にアクセスするが、ユーザースレッド同士は排他的でない。
どのように排他処理を実装すればよいか。
>>419 Producer-Consumerパターンか
間にChannel挟めばちゃんと動くよ
2コア4スレッドってCPUだと
4スレッド同時に動くの?
動くよ
ただしハードウェアリソース的に余裕がある部分(SSEとか)位しかあまり効果がないな
マルチスレッドではやや分がある
というのはコンテキストスイッチの負荷が純粋に1/2になる
レジスタの内容をメモリに退避する回数が1/2になればそりゃ軽くなるよね
整数演算ではあまり期待しない方がいい
同時に動いてないなら排他制御しなくていいみたいな勘違いしてそうな質問だ。
そこまで深くは考えてなかったんだけど。
CPUコアひとつなのにどうやって2スレッド同時に動くのか不思議だったから。
実際に鯖用CPUではHT切ってあるもんな
かえってパフォーマンスが低下するとかで
最近の例の脆弱性との絡みもある
その代わり最初からコアいっぱい積んでいる
on/offをアプリ側で指定できないし、
性能が線形に上がらない時点でHTを考慮した設計は面倒すぎる。
マルチスレッド・デザインパターンの本にあった例だけど
ワーカースレッド(スレッドプール)を実装せよ
なお言語は自由とする
マルチスレッドの解説本はいくつもあるけど
マルチプロセッサのプログラミングって参考書ないのかね。
マルチスレッドの解説本でカバー出来ないくらいのマルチプロセッサのプログラミングだと
かなりマニアックというかプロセッサ固有の問題の割合が大きくなると思うので
そういう方面で探すしかないのではないか
それだけに特化した専門書は無いかもね
行列演算を並列処理とかそういう粒度の細かな並列化の話ばっかりで。
せっかく10コアとかあるんだから、各コアに別々のプログラムを走らせておいて
同期しながら処理とかしたいんだけどどうするのがいいかよく分からない。
fork させてメッセージやりとりすれば良さそうなんだけど。
やりたいことがちょっと特殊かもね。
質問の低レベル化が甚だしい。アセンブラを勉強して基礎固めを。
OpenMPみたいなのを手動でやるって話かな
マルチコアだとメモリ帯域がボトルネックになりやすいから
巨大な行列計算は少し粒度を荒くしたMPIの方が強いよね
10コアとかいってるからマルチプロセッサというよりメニーコア活用術?
>>433 むしろアセンブラのほうが分かりやすいんだけど。
各コアにPCセットして起動すればいいの?
プロセッサの仕様書読んでみるわ。
マルチスレッドの排他処理で詰まってスレ検索して来てみたけどこのスレは高尚過ぎるなw
初心者スレにでも行こう
_beginthreadex() を使ったマルチスレッドプログラムについて質問です。
この関数の説明を見ると、「_beginthreadex() のコールに成功すると、スレッドのために
タイムスライスが割り当てられたか否かによらず、スレッドはアクティブ(non-signal)になる」
とあったのですが、_beginthread() がスレッドハンドルを返すよりも前にスレッド関数内の
処理が実行される(完了する)ことはありえますか?
>成功した場合、これらの各関数は、新しく作成されたスレッドへのハンドルを返します。ただし、新しく作成されたスレッドが短時間で終了した場合、 _beginthread は有効なハンドルを返さない可能性があります。 (「解説」の説明を参照してください)。
>_Beginthread よりも _beginthreadex を使用する方が安全です。 _Beginthread によって生成されるスレッドが短時間で終了した場合は、 _beginthread の呼び出し元に返されるハンドルが無効であるか、別のスレッドを指している可能性があります。 ただし、 _beginthreadex によって返されるハンドルは _beginthreadex の呼び出し元によって閉じられる必要があるため、 _beginthreadex がエラーを返さなかった場合は、有効なハンドルであることが保証されます。
ハンドルが有効であることは保証されているけど
実行順についての言及はないし、
そもそも別スレッドなら、どちらが先に行われるかについては何の保証もないと考えるべきじゃないのかな
「APIから戻る」のだって実行権がなければ後回しにされる可能性はあるんだから
>>440 ご返信ありがとうございます。概ね理解できました。
勉強不足で、マルチスレッドの仕組みについて誤解していたようです。
ちなみにCentOSはスレッドのコアが指定できるよ。
あわしろ氏によると、Macは既にオワコンなので、WSLを使うと良いらしい。
針に糸を通す( thread a needle
糸をつむぐ( spin thread [yarn]
糸が切れた( The thread broke.
琴の糸を締める( tighten a string of a koto
糸をかき鳴らす( strum the strings
マルチスレッド処理の花形といえばハードなリアルタイムスレッドとバックグラウンドスレッドの間のデータのやり取りだと思ってるんだが
スレの過疎っぷりを見るに、殆どの人にとって必要のないものだったんだな
>>447 MS-DOS のデバイスドライバにでも痕跡が残っていたような‥
どうするつもりだったんだろう?
>>447 ハードな略が動いている間はバック略を動かさないから大して考えることは無い
DOSの頃と同じだな
>>432 とりあえず、メインスレッド1個にサブスレッドを9個用意し、基本的な管理はメインスレッド管理。
イベントハンドルは9×2個用意する。
サブスレッドはイベント処理とWaitForSingleObjectで待たせておいて、メインスレッドから情報を送って
SetEventでイベントを動かす。メインスレッドはサブスレッド9個からSetEventでイベントが返らない限り
イベントとWaitForSingleObjectを駆使して止めておく。
>>432 とりあえず、メインスレッド1個にサブスレッドを9個用意し、基本的な管理はメインスレッド管理。
イベントハンドルは9×2個用意する。
サブスレッドはイベント処理とWaitForSingleObjectで待たせておいて、メインスレッドから情報を送って
SetEventでイベントを動かす。メインスレッドはサブスレッド9個からSetEventでイベントが返らない限り
イベントとWaitForSingleObjectを駆使して止めておく。
>>450-451 あ”、二重投稿になったか。
えっと、ちょっと補完。
サブスレッドの処理についてはループして待たせておく。終わったら終了を知らせるイベントを発生させる。
>>365
REID 1 みたいな例があるから必ずしも昔の技術というわけではないな。
>>16 あれって、OSの機能だから気にしなくても良いというのでは駄目か?
1000msecでコンテキストスイッチ何回発生するんだこれ
ここで multi process な質問は反則?
高級言語しか使えない身で話すけど
Pythonで超重量級のCPU処理とOpenAIに対するリクエストで数秒I/Oに飛ぶ処理の二つがそれぞれタスクに分解されてるとき、
前者のタスクが処理完了すると後者のタスクで数個~数十個くらいタスクが新規作成されて、(c, c, c, i, i, i, i, i, i, c, i, i,...)
内部どうなってるのか知らんけどI/OでGIL解放されても後続のタスクが何個も後者のタスクだから前者のタスクがくそ遅延するってあり得る?
両者のタスクを別々のプロセスに切り分けたら前者のタスクが遅延するとかいうことなくなったんだけどさ
そういう場合
同じ状況になる再現コードを貼りましょう
5次方程式に新公式を発見:ルートを超える新理論
2025.05.14 17:05:56 WEDNESDAY
https://nazology.kusuguru.co.jp/archives/177496 >>オーストラリアのニューサウスウェールズ大学(UNSW)で行われた研究
プログらまーも覚えるとよい
125年越しに解決したかもしれない「ヒルベルトの第6問題」とは?
2025年05月10日 15時00分
https://gigazine.net/news/20250510-hilberts-6th-problem-solved/