簡體   English   中英

如何將此代碼重構為多線程版本?

[英]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};
        //.....
    }

其中mPhoton的成員,那么即使獲得任何東西也很少。 如果(在另一個極端) 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM