C++ C++;多线程比单线程慢

C++ C++;多线程比单线程慢,c++,multithreading,boost,C++,Multithreading,Boost,我有一些这样的代码: class MyTask { public: run(size_t pool_size) { ... // do some pre things std::vector<std::string> name_list=read_a_list(); // read task list std::vector<std::pair<std::string, double>> result_

我有一些这样的代码:

class MyTask {
public:
    run(size_t pool_size) {
        ... // do some pre things
        std::vector<std::string> name_list=read_a_list(); // read task list

        std::vector<std::pair<std::string, double>> result_list; // name & time

        boost::thread_pool pool(pool_size); // "pool_size" threads in pool
        size_t max_task=2*pool_size;        // max "2*pool_size" tasks in queue
        size_t task_number=0;               // using task_number to limit the number of tasks in queue
        boost::mutex task_number_mu;
        boost::condition_variable_any task_number_condition;

        for(size_t idx=0;idx<name_list.size();++idx){
             boost::unique_lock<boost::mutex> out_lock(task_number_mu);
             task_number_condition.wait(out_lock, [&] {
                 return task_number < max_task;
                 });
             ++task_number;
             boost::asio::post(pool,
                  [&,idx] {
                      {
                          boost::unique_lock<boost::mutex> in_lock(task_number_mu);
                          --task_number;
                          task_number_condition.notify_one();
                      }
                      std::string name=name_list[idx];
                      Timer timer; // a class using std::chrono to collect time
                      timer.Start();

                      A a=read_A_data(name+"_a.csv"); // one file
                      timer.Stop();
                      double time_a=timer.Elapsed();

                      B b=read_B_data(name+"_b"); // many files in "name_b" directory
                      timer.Stop();
                      double time_b=timer.Elapsed();

                      result_type result=do_some_selection(a,b); // very expensive function
                      timer.Stop();
                      double time_r=timer.Elapsed();

                      write_result(result,name+"_result.csv"); // one file
                      timer.Stop();
                      double time_w=timer.Elapsed();

                      ... // output idx, time_{a,b,r,w} by boost log

                      {
                           boost::lock_guard<boost::mutex> lock(result_list_mu);
                           result_list.emplace_back(std::make_pair(name,time_w));
                      }
                });//post
           }//for
      pool.join();
      ... // do some other things
   } //run

public :
   static A read_A_data(const std::string& name_a){
         ... // read "name_a" file, less than 1.5M 
   }
   static B read_B_data(const std::string& name_b){
         ... // read files in "name_b" directory, more than 10 files, 1M~10M per file
   }
   static result_type do_some_selection(A a,B b){
         result_type result;
         for(const auto& i:b){
              for(const auto& j:a){
                   if(b_fit_in_a(i,j)){ //b_fit_in_a() does not have loops
                       result.emplace_back(i);
                   }//if
              }//for j
         }//for i
         return result;
   }
   static void write_result(const result_type& result, const std::string& name_r){
         ... // write result to "name_r", about 2M~15M
   }
}
我有一个Xeon-W是16C32T,所以将
pool\u size
设置为8,并且:

1 14.7919 2685.21 6600.4 7306.15
2 16.0127 2311.94 10517.2 12044.3
3 7.4403 2111.83 6210.49 7014.61
4 9.0292 2165.12 10482.5 11893
5 16.6851 1664.2 17282.7 20489.9
6 32.9876 6488.17 25730.6 25744.7
...
第16组,以及:

1 22.5189 5324.67 18018.6 20386
2 17.1096 8670.3 21245.8 23229.1
3 17.9065 10930.7 27335.3 29961.55
4 20.6321 5227.19 30733 34926
5 25.104 2372.04 13810.9 15916.7
6 39.6723 18734.3 79300.1 79393.5
...
第32组,以及:

1 39.3981 19159.7 43451.7 44527.1
2 51.1908 5693.48 43391.3 50314.4
3 42.4458 18068.6 59520.6 67359.4
4 44.1195 29214.7 70312.4 76902
5 64.1733 23071.1 86055.2 86146.7
6 44.1062 36277.5 89474.4 98104.7
...

我知道多线程程序经常有磁盘读/写问题,这解释了
时间a
时间b
时间w
的增加。但让我困惑的是,
时间也增加了很多
do_some_selection
是一个静态成员函数,因此我认为线程不会相互作用,但似乎我使用的线程越多,一项任务花费的时间就越长。我做错了什么?如何使这些任务并行?

首先,您应该以合理的方式显示数据。事实上,很难做出任何评估。就像打印时差一样,这样我们就可以很容易地看到每个任务花费了多少时间,而不是“从任务开始经过了多少时间”

其次,您运行的任务主要是磁盘读/写,并且不太可并行化。因此,总执行时间不会有太大变化。 当你安排几个不相关的任务时——如果是一个线程,它们将在几乎相同的时间完成。但是,由于您运行多个线程,每个任务都会争夺资源,因此会延迟每个任务的完成,直到大多数任务完成


关于为什么“仅无关计算”的速度变慢。这在很大程度上取决于您执行的计算。除了一些一般的原因外,现在不能说太多。从外观上看,您执行了一些内存操作。RAM内存访问受到内存总线的限制,通常速度较慢。在单线程情况下,大量数据仍然可以存储在处理器的内存缓存中,大大加快了处理数据所需的时间。但这只是对原因的一般猜测。您应该进行更深入的分析以找到瓶颈-在PC处理器上,内存总线应该足以容纳多个线程。

尝试了
tbb::parallel_for
tbb::parallel_for_for each
而不是
boost::thread_pool
,但在这么长的时间内没有任何变化。我最后想可能是因为“分配竞争”之类的原因。
result.emplace_back(i)
可能会使所有线程中的
result
s越来越大,并且可能会使为它们分配更多内存变得更加困难。现在我想通过使用<代码>推力>代码>或<代码> TBB</代码>,而不是同时执行多个任务来完成<代码> dothOnthAsvestOnCudiy()/Cuff>并行化的任务。感谢您的回答,这对您帮助很大。@SATMOS关于优化
做一些选择()
-在多线程上优化之前,您应该先阅读有关内存缓存线以及与之相关的问题,如“错误共享”。否则,它可能会变得更慢。@ SATMOS关于多磁盘加载/读取任务的固定问题——考虑生成一个执行器(只是一个线程池),用一个或两个线程负责读/写磁盘上的数据,在磁盘上调度所有读/写任务,以减轻与之相关的问题。
1 39.3981 19159.7 43451.7 44527.1
2 51.1908 5693.48 43391.3 50314.4
3 42.4458 18068.6 59520.6 67359.4
4 44.1195 29214.7 70312.4 76902
5 64.1733 23071.1 86055.2 86146.7
6 44.1062 36277.5 89474.4 98104.7
...