并行执行比顺序执行快的示例

Example in which parallel execution is faster than sequential execution

本文关键字:执行 顺序 并行执行      更新时间:2023-10-16

我正在寻找一个并行执行比顺序执行更快的例子(在c++中)。我尝试了一些方法:

快速排序

计算1000000个素数,

NxN矩阵反演

但是顺序执行总是更快。正如您所看到的,我使用两个相同的线程来执行threadWrapper(int threadNo)

中的代码。
#include <iostream>                                                             
#include <ctime>                                                                
#include <thread>                                                               
using namespace std;
void threadWrapper(int threadNo) {                                              
  clock_t start = clock();                                                    
  cout << "thread " << threadNo << ": started" << endl;                       
  // do something crazy                                                                        
  clock_t ends = clock();                                                     
  cout << "thread " << threadNo << ": has finished, elapsed time " << (double)(ends-start)
}
int main() {                                                                       
  cout << "SEQUENTIALLY:" << endl;                                               
  clock_t seq_start = clock();                                                   
  threadWrapper(1);                                                              
  threadWrapper(2);                                                              
  clock_t seq_ends = clock();                                                    
  cout << "sequentially: elapsed time " << (double)(seq_ends-seq_start)/CLOCKS_PER_SEC <
  cout << endl << "PARALLEL:" << endl;                                           
  clock_t para_start = clock();                                                  
  thread first(threadWrapper, 1);                                                
  thread second(threadWrapper, 2);                                               
  first.join();                                                                  
  second.join();                                                                 
  clock_t para_ends = clock();                                                   
  cout << "parallel: elapsed time " << (double)(para_ends-para_start)/CLOCKS_PER_SEC << 
  return 0;                                                                      
}

你有什么建议吗?

摘自Cpp Reference on std::clock here:

返回进程从与程序执行相关的实现定义时代开始以来所使用的处理器时间的近似值。

您正在进行的测量是处理时间,而不是挂钟时间。线程化并不需要更少的 cpu(它实际上需要更多),但是你可以并行地做更多的事情,这意味着从用户的角度来看,它运行更快

。如果每个threadWrapper花费1s,两个计数将指向大约2秒(顺序vs并行),但整个过程将在3秒内完成。

在处理线程和并行处理时,请记住以下注意事项:

  • I/O是瓶颈。
  • 内存通常是瓶颈。
  • 管理线程需要开销

添加线程可能不会提高应用程序的速度,但它们肯定会使应用程序变得更复杂。

I/O瓶颈
访问I/O,无论是硬盘驱动器、来自摄像机的数据,还是通过蓝牙发送,都会导致线程等待。如果正确写入,操作系统将挂起线程,直到I/O准备好。这也会发生在单线程程序中。

除非你的程序在等待I/O时有事情要做,否则并行线程在这里不起作用。你只会给RTOS带来更多的工作。

内存瓶颈/争用
在大多数具有多个处理器内核的个人电脑和嵌入式应用程序中,它们通常共享内存(在芯片外部)。当一个核心想要访问内存的同时另一个核心访问内存时,可能会有争用。一个线程(核心)必须等待另一个线程完成(或交织请求)。这种争论可能会使您失去本以为可以获得的效率。大多数处理器都在向内存和内存之间传输数据,大量使用共享数据总线。

图形处理单元使程序更高效,因为它有自己的内存。当你告诉GPU动画一个对象时,GPU使用它的内存,这消除了与CPU内存的争用。因此,有大量的性能增益。

线程管理开销
线程的创建、维护和销毁都有开销。对于单线程或核心应用程序,RTOS可以将其分配给CPU并等待它结束。不需要额外的努力。对于多核,现在RTOS必须在两个核之间切换"线程",并监视除默认核之外的另一个核的资源请求和争用。

一个线程应该执行足够的执行,使线程的创建和维护值得。如果额外的线程可以从主CPU中卸载大量的活动,那么它们是值得的。例如,将两个数字相加并返回总和的线程太简单,不值得使用。将文件读入内存的线程是值得的。


多核和多线程并不能神奇地执行任务。它们有创建、操作和销毁的开销。经验法则是创建额外的线程,如果它们可以从主cpu异步卸载工作,并且它们经常被使用。

任何持续地耗尽TLB或以其他方式必须等待间歇到突发的主存活动。(*编辑:越接近停滞的持续时间与生产间隔之间,更多的提升并行性将得到。你可能还记得这是缓冲I/O的数学…是的。现在主存是一种I/O设备