有一个循环需要很长时间,我正在考虑将此代码重构为多线程版本。这是模型。
Photon photon;
for (int i=0;i<1000000;++i){
func(){
photon.lanuch(args...){
// do something
}
}
}
我必须将这个函数调用一千零一千次。所以我想知道如何在某个时候创建一些线程来运行这个函数。 但光子必须每次都是个体。 我可以将索引转换为:
atomic<int> i{0};
while(i<1000000){
func(){
photon.lanuch(args...){
// do something
++i;
}
}
}
答案 0 :(得分:2)
非常多的取决于photon.launch()
如何以及在多大程度上可以并行化。
下面的代码将范围划分为(大约)相等的段,然后在单独的线程中执行每个段。
如上所述,这有助于取决于photon.launch()
可以并行完成多少。如果它花费大部分时间修改共享状态,并且基本上具有以下形式:
void launch(int index){
std::lock_guard<std::mutex> guard{m};
//.....
}
如果m
是Photon
的成员,则很少会获得任何内容。
如果(在另一个极端),对launch
的个别呼叫永远不会争用相同的数据,那么它可以并行化到系统可以提供的核心数量。
#include <thread>
#include <vector>
class Photon {
public:
void launch(int index){
//... what goes here matters a lot...
}
};
void photon_launch(Photon& photon,int from,int to){
for(auto i=from;i<=to;++i){
photon.launch(i);
}
}
int main() {
const size_t loop_count=100000;//How big is the loop?
const size_t thread_count=4;//How many threads can we utilize?
std::vector< std::thread > threads;
Photon photon;
int from=1;
for(size_t i=1;i<=thread_count;++i){
//If loop_count isn't divisible by thread_count evens out the remainder.
int to=(loop_count*i)/thread_count;
threads.emplace_back(photon_launch,std::ref(photon),from,to);
from=to+1;
}
//Now the threads are launched we block until they all finish.
//If we don't the program may (will?) finish before the threads.
for(auto& curr : threads){
curr.join();
}
return 0;
}
答案 1 :(得分:2)
使用线程,你必须注意对象的生命周期和分享远远超过正常。
但基本的解决方案是
void do_tasks( std::size_t count, std::function<void( std::size_t start, std::size_t finish )> task ) {
auto thread_count = std::thread::hardware_concurrency();
if (thread_count <= 0) thread_count = 1;
std::vector<std::future<void>> threads( thread_count-1 );
auto get_task = [=](std::size_t index) {
auto start = count * index / thread_count;
auto finish = count * (index+1) / thread_count;
// std::cout << "from " << start << " to " << finish << "\n";
return [task, start, finish]{ task(start, finish); };
};
for( auto& thread : threads ) {
auto index = &thread-threads.data();
thread = std::async( std::launch::async, get_task(index) );
}
get_task( threads.size() )();
for (auto& thread : threads) {
thread.get();
}
}
这是一个小型多线程库。
你这样使用它:
do_tasks( 100, [&](size_t start, size_t finish) {
// do subtasks starting at index start, up to and not including finish
});
还有其他更复杂的线程库,但是写一个小的一半也不难,所以我做了。
明确:
Photon photon;
do_tasks( 1000000, [&](size_t start, size_t finish) {
for (int i = start; i < finish; ++i) {
photon.lanuch(args...){
}
});
但是你必须非常小心,确保线程之间没有不安全的数据共享,并且你不只是阻塞常见互斥锁上的每个线程。