简体   繁体   中英

How can I refactor this code into multi-thread version?

There is a loop which takes quite a long time and I'm considering refactoring this code into multi-thread version. And here is the model.

   Photon photon;
    for (int i=0;i<1000000;++i){
         func(){
          photon.lanuch(args...){
          // do something  
          }
      }
    }

I have to call this function a thousand and thousand times.So I was wondering how can I create some threads to run this function at the some time. But the photon have to be individual every single time. the index i can be converted to this:

 atomic<int> i{0};
    while(i<1000000){
          func(){
              photon.lanuch(args...){
              // do something  
             ++i;
               }
          }
    }

A awful lot depends on how and to what extent photon.launch() can be parallelised.

The code below divides a range into (approximately) equal segments and then executes each segment in a separate thread.

As stated whether that helps will depend on how much of photon.launch() can be done in parallel. If it spends most of its time modifying a shared state and essentially has the form:

    void launch(int index){
        std::lock_guard<std::mutex> guard{m};
        //.....
    }

Where m is a member of Photon then little if anything will be gained. If (at the other extreme) the individual calls to launch never contend for the same data then it can be parallelised up to the number of cores the system can provide.

#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;
}

With threading you have to pay attention to object lifetime and sharing far more than normal.

But the basic solution is

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();
  }
}

This is a little multi threading library.

You use it like this:

do_tasks( 100, [&](size_t start, size_t finish) {
  // do subtasks starting at index start, up to and not including finish
});

There are other more complex threading libraries, but writing a small half-decent one isn't hard so I did it.

To be explicit:

Photon photon;
do_tasks( 1000000, [&](size_t start, size_t finish) {
  for (int i = start; i < finish; ++i) {
    photon.lanuch(args...){
  }
});

but you'll have to be extremely careful making sure there is no unsafe data sharing between the threads, and you aren't just blocking each thread on a common mutex.

Live example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM