前提・実現したいこと
2つの同じサイズのvectorの同一性の比較としてthreadを作ったのですが,想定に反して速くありません。何が問題なのかお分かりになる方がいらっしゃれば教えてください。
構造は至って単純です。
・elapsed_time_dblは時間計測用テンプレート関数
・is_eq_ob スレッド管理クラス ,!=を見つけたときのスレッド中止用フラッグとしてatomicを使用。結果判定返却用として兼用。
該当のソースコード
C++
1#include <thread> 2#include <chrono> 3#include <vector> 4using namespace std; 5template<class TimePoint> 6double elapsed_time_dbl(const std::string& msg, const TimePoint& start) { 7 auto end=std::chrono::high_resolution_clock::now(); 8 std::chrono::duration<double, std::milli> fp_ms = end-start; 9 std::cout << msg <<" : " << fp_ms.count()<<" ms\n"; 10 return fp_ms.count(); 11} 12class is_eq_ob{ 13 int size; 14 const vector<int>& m_a; 15 const vector<int>& m_b; 16 atomic<bool> m_loop_end; 17public: 18 is_eq_ob(const vector<int>&a, const vector<int>&b): 19 m_a{a},m_b{b},m_loop_end{false},size{(int)a.size()}{} 20 21 void comp_thread(int st, int count ){ 22 for(int i=0;i < count;i++){ 23 if(m_loop_end.load()) 24 return ; 25 if( m_a[st+ i] != m_b[st+ i] ){ 26 m_loop_end.store(true); 27 return ; 28 } 29 } 30 } 31 bool go(){ 32 33 vector<thread> th_s; 34 int div = 10; 35 ///divの数のスレッド生成,sizeをdiv数で分割してブロックごとに処理 36 for(int d=0;d < div;d++){ 37 int start = size * d/div;//スレッドに渡す開始位置 38 int end = (d==div-1) ? size: size*(d+1)/div;//スレッドに渡す終了位置 39 thread a(&is_eq_ob::comp_thread,this, start, end - start); 40 th_s.push_back( move(a) ); 41 } 42 43 for(auto& th: th_s) 44 th.join(); 45 46 return !m_loop_end.load(); 47 } 48}; 49 50 51int main(){ 52 53 vector<int> a(1000,0); 54 vector<int> b(1000,0); 55 //a[100]=1; 56 57 auto start=std::chrono::high_resolution_clock::now(); 58 cout << (a==b)<<'\n'; 59 elapsed_time_dbl("a==b", start); 60 61 is_eq_ob is_eq(a,b); 62 start=std::chrono::high_resolution_clock::now(); 63 cout << is_eq.go() <<'\n'; 64 elapsed_time_dbl("is_eq_ob", start); 65 return 0; 66}
試したこと
結果は次のように常にスレッドの方が遅くなります。
1
a==b : 0.064569 ms
1
is_eq_ob : 0.37863 ms
配列の規模が小さすぎるので、スレッド化するコストのほうが上回ってしまっているのでは?
オーバーヘッドですよね。たしかにそうなんですが,この例では,そうなりますね。サイズを1000000にすると,
1
a==b : 1.91292 ms
1
is_eq_ob : 0.519138 ms
となります。
mainにコメント行を入れてあり,これを外して100の位置に不整合となる値を入れると,
0
a==b : 0.071875 ms
0
is_eq_ob : 0.333058 ms
となり,少なくともスレッド1は早めに戻ってくると思うのですが,これもオーバーヘッドなんですかね。
そっちの方は全スレッド終了待機のオーバーヘッドだと思います。
確認方法としては、以下のようにして不整合判定時に時間を出力すると非マルチスレッド版と同程度になると思います。
スレッド使う開始時間は上の方に別の高域変数として定義しておいて、
using namespace std;
static std::chrono::high_resolution_clock::time_point thread_start;
スレッドの方の開始時間をセットしてから開始、
thread_start = std::chrono::high_resolution_clock::now();
is_eq_ob is_eq(a,b);
あとは不整合判定直後に出力する。
if( m_a[st+ i] != m_b[st+ i] ){
elapsed_time_dbl("is_eq_ob", thread_start);
もちろんこのやり方だと複数回不整合出力されてしまう可能性のあるコードとなりますが、
全スレッド終了待機に時間がかかっていることが分かればあとはやり方次第です。
そうなんです。私もやってみました。どうやら,早期に不一致を検出しているにもかかわらず,全部のスレッドの終了まで待機させられているようなんですね。そこまでわかったのですが,これを回避する手段がみつからなくて...。
回答3件
あなたの回答
tips
プレビュー