[英]How can I refactor this code into multi-thread version?
有一個循環需要很長時間,我正在考慮將此代碼重構為多線程版本。 這是模型。
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;
}
}
}
非常多的取決於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;
}
使用線程,你必須注意對象的生命周期和共享遠遠超過正常。
但基本的解決方案是
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...){
}
});
但是你必須非常小心,確保線程之間沒有不安全的數據共享,並且你不只是阻塞常見互斥鎖上的每個線程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.