C++ 2011には非常にクールな新機能が含まれていますが、forループを並列化するための多くの例は見つかりません。 私の非常に素朴な質問は、単純なforループ( "omp parallel for"をstd :: threadと同じように)をどのように並列化するのですか? (私は例を探します)。C++ 2011:std :: thread:ループを並列化する簡単な例?
ありがとうございました。
C++ 2011には非常にクールな新機能が含まれていますが、forループを並列化するための多くの例は見つかりません。 私の非常に素朴な質問は、単純なforループ( "omp parallel for"をstd :: threadと同じように)をどのように並列化するのですか? (私は例を探します)。C++ 2011:std :: thread:ループを並列化する簡単な例?
ありがとうございました。
std::thread
は必ずしもループを並列化する必要はありません。これはparallel_forアルゴリズムのような構造を構築するための低レベルの抽象化を意図しています。ループを並列化したい場合は、parallel_forアルゴリズムを自分で実行するか、タスクベースの擬似を提供する既存のlibraireを使用する必要があります。
次の例は、単純なループを並列化する方法を示していますが、反対側には欠落しているロードバランシングや単純なループの複雑さなどの欠点も示しています。parallel_for
テンプレートを提供していますライブラリを使用して
typedef std::vector<int> container;
typedef container::iterator iter;
container v(100, 1);
auto worker = [] (iter begin, iter end) {
for(auto it = begin; it != end; ++it) {
*it *= 2;
}
};
// serial
worker(std::begin(v), std::end(v));
std::cout << std::accumulate(std::begin(v), std::end(v), 0) << std::endl; // 200
// parallel
std::vector<std::thread> threads(8);
const int grainsize = v.size()/8;
auto work_iter = std::begin(v);
for(auto it = std::begin(threads); it != std::end(threads) - 1; ++it) {
*it = std::thread(worker, work_iter, work_iter + grainsize);
work_iter += grainsize;
}
threads.back() = std::thread(worker, work_iter, std::end(v));
for(auto&& i : threads) {
i.join();
}
std::cout << std::accumulate(std::begin(v), std::end(v), 0) << std::endl; // 400
、あなたが可能同時アクセスなしがないことを確認している場合、ある、ループを並列化する最も簡単な方法は私の知る限り
parallel_for(std::begin(v), std::end(v), worker);
私たちは依然としてpthreadを主に使用しているので、C++ 11固有の答えは提供できません。しかし、言語にとらわれない答えとして、別の関数(スレッド関数)で実行するように設定して並列化します。言い換えれば
、あなたのような機能を持っている:
def processArraySegment (threadData):
arrayAddr = threadData->arrayAddr
startIdx = threadData->startIdx
endIdx = threadData->endIdx
for i = startIdx to endIdx:
doSomethingWith (arrayAddr[i])
exitThread()
と、メインのコードで、あなたは2つのチャンクに配列を処理することができます。
int xyzzy[100]
threadData->arrayAddr = xyzzy
threadData->startIdx = 0
threadData->endIdx = 49
threadData->done = false
tid1 = startThread (processArraySegment, threadData)
// caveat coder: see below.
threadData->arrayAddr = xyzzy
threadData->startIdx = 50
threadData->endIdx = 99
threadData->done = false
tid2 = startThread (processArraySegment, threadData)
waitForThreadExit (tid1)
waitForThreadExit (tid2)
(心の中で警告を保ちますスレッド1がローカルストレージにデータをロードしていることを確認する必要がありますメインスレッドはスレッド2、おそらくはミューテックスまたはの配列の構造スレッドごと)。それは、並列に実行されるようにそれがいいだろうけれどもつまり
が、それは、めったにだけfor
ループを変更するだけの簡単な作業ですしない、のようなもの:
for {threads=10} ({i} = 0; {i} < ARR_SZ; {i}++)
array[{i}] = array[{i}] + 1;
は代わりに、再配置のビットを必要としますスレッドを利用するコード
もちろん、データを並行して処理することが理にかなっていることを確認する必要があります。各配列要素を前の配列要素に1を加えたものに設定している場合、前の要素が最初に変更されるのを待たなければならないため、並列処理は必要ありません。
上記の特定の例では、スレッド関数に渡される引数を使用して、配列のどの部分を処理するかを指定しています。スレッド関数自体には、作業を行うループが含まれています。
明らかに、ループの機能、パラレル化の選択方法、スレッドの有効期間の管理方法によって異なります。
私はthe book from the std C++11 threading libraryを読んでいる(それはまたboost.threadメンテナの一つであり、Just Threadを書いた)、私は「それが依存」ことがわかります。
新しい標準のスレッドを使用して基礎を理解するために、たくさんの例があるので、この本を読むことをお勧めします。 また、http://www.justsoftwaresolutions.co.uk/threading/とhttps://stackoverflow.com/questions/415994/boost-thread-tutorials
に単純化することができますOpenMPを使用します。
これは、LLVMを除くすべての主要コンパイラでサポートされています(2013年8月現在)。
例:
for(int i = 0; i < n; ++i)
{
tab[i] *= 2;
tab2[i] /= 2;
tab3[i] += tab[i] - tab2[i];
}
これは、このように非常に簡単に並列化することになります。
#pragma omp parallel for
for(int i = 0; i < n; ++i)
{
tab[i] *= 2;
tab2[i] /= 2;
tab3[i] += tab[i] - tab2[i];
}
しかし、これは、値の大きな数でのみ効率的であることに注意してください。
あなたがg ++、ラムダとfor_eachを使用して、および(シーンの後ろのOpenMPを使用することができます)、GNU並列拡張機能を使用することだろうを行うための別の非常にC++ 11-っぽい道を使用する場合:
__gnu_parallel::for_each(std::begin(tab), std::end(tab), [&]()
{
stuff_of_your_loop();
});
を
しかし、for_eachは主に配列やベクトルなどのために考えられます。 Range
クラスとbegin
クラスとend
メソッドを作成することで範囲を繰り返し処理したい場合は、主にintをインクリメントします。
数学的な処理を行う単純なループでは、#include <numeric>
と#include <algorithm>
のアルゴリズムをすべてG ++と並列化することができます。
あなたがそれを行うことができthisクラスを使用するよう:
Range based loop (read and write)
pforeach(auto &val, container) {
val = sin(val);
};
Index based for-loop
auto new_container = container;
pfor(size_t i, 0, container.size()) {
new_container[i] = sin(container[i]);
};
リンクが再び機能します。 –
このクラスは利用できません(404)。どのクラスを使用するかを詳しく教えてください。 – BernhardWebstudio
のstd ::スレッドとラムダ式を使用してマクロ定義:
#ifndef PARALLEL_FOR
#define PARALLEL_FOR(INT_LOOP_BEGIN_INCLUSIVE, INT_LOOP_END_EXCLUSIVE,I,O) \ \
{ \
int LOOP_LIMIT=INT_LOOP_END_EXCLUSIVE-INT_LOOP_BEGIN_INCLUSIVE; \
std::thread threads[LOOP_LIMIT]; auto fParallelLoop=[&](int I){ O; }; \
for(int i=0; i<LOOP_LIMIT; i++) \
{ \
threads[i]=std::thread(fParallelLoop,i+INT_LOOP_BEGIN_INCLUSIVE); \
} \
for(int i=0; i<LOOP_LIMIT; i++) \
{ \
threads[i].join(); \
} \
} \
#endif
用法:
int aaa=0;
PARALLEL_FOR(0,90,i,
{
aaa+=i;
});
その醜いが、できます。
forループに重要なセクションはありますか? –
OMGをもっと見ると、std :: threadはそれを置き換えるものではないと思います。 'std :: thread'は、低レベルのCRUD操作を最適化するためのものではありません。 –
並列化しようとしているループを投稿できますか? –