多核开发入门指南

一、为什么需要多核开发?

        答案很简单,目前的芯片制造技术对CPU主频的提升已经达到一个极限了,也就是说性能的垂直伸缩已经不太可能了。因此通过多核的方法,可以让程序横向的伸缩,这就类似于用多台服务器实现负载均衡(水平伸缩),而不是简单的靠将服务器升级成小型机来提供处理能力(垂直伸缩)。

        虽然多核并行计算的概念已经存在了几十年了,但直到最近多核CPU在PC上的普及,多核开发才不得不提引起程序员的重视。

        多核开发的本质就是使用多线程进行程序开发,我们在学数据结构和算法的时候,写的所有的算法都是面向单线程的。而多核开发的目的就是将这些算法改造成多线程的支持,然后系统运行时将这些多线程平均分配到多核处理器上,以实现运行的加速。

 

二、如何进行多核开发

      如果你很熟悉POSIX threads (pthreads) 或者 WinAPI threads,你就可以自己进行开发。
      如果你不想设计过多底层的线程操作,那就选择一个并发开发平台,由平台来自动协调,调度和管理多核资源。并发开发平台包括各种线程池的库,例如
          .NET的ThreadPool类
          Java的Concurrent类
          消息传递环境,例如MPI
          data-parallel编程环境,例如NESL, RapidMind, ZPL
          task-parallel编程环境, 例如Intel的Threading Building Blocks (TBB) 和 Microsoft的Task Parallel Library (TPL)
          动态编程环境,例如Cilk or Cilk++或者业界标准OpenMP. 
    这些并发平台通过提供语言抽象,扩充注释或者提供库函数的方式来支持多核开发。

 

三、使用并发开发平台具体有哪些好处

      我们从下面几个方面来看:

      软件开发中最重要的三个考虑的要素就是
              程序的性能 (使用多核就是为了提升程序的性能的)
              开发的时间
              程序的可靠性

      而其中影响开发时间的三个要素是

                 伸缩性:如果你自己编写线程,你必须考虑用户是双核,四核还是八核。如何将线程自动适应用户的核数,并且在多核上将线程均衡的负载。
                 代码简洁:直接使用底层线程库操作代码是十分复杂的
                 模块化:直接使用底层线程库操作还会破坏代码的模块化

 

四、具体实例

          下面以Fibonacci的例子来演示:它的递归算法经常被用来作为多核开发的例子。


          单核时代,我们写Fibonacci代码的方法如下:

  1. int fib(int n) 
  2. {
  3.   if (n < 2) return n;
  4.  else {
  5.       int x = fib(n-1);
  6.       int y = fib(n-2);
  7.       return x + y;
  8.      }
  9. }       
  10.                 
  11. int main(int argc, char *argv[])
  12. {       
  13.   int n = atoi(argv[1]);
  14.  int result = fib(n);
  15.  printf("Fibonacci of %d is %d./n", n, result);
  16.  return 0;
  17. }

       这个算法的核心就是f(n) = f(n-1) + f(n-2),当n很大时,我们希望计算f(n-1)和f(n-2)这两个任务能否分摊在一个双核处理器上同时执行。

 

       如果直接使用WinAPI-threaded操作的代码如下:


  

  1.       int fib(int n)
  2.  {
  3.    if (n < 2) return n;
  4.    else {
  5.     int x = fib(n-1);
  6.     int y = fib(n-2);
  7.      return x + y;
  8.      }
  9.  }
  10.      
  11.  typedef struct {
  12.        int input;
  13.        int output;
  14.      } thread_args;
  15.      
  16.   void *thread_func ( void *ptr )
  17.   {
  18.     int i = ((thread_args *) ptr)->input;
  19.     ((thread_args *) ptr)->output = fib(i);
  20.     return NULL;
  21.   }
  22.       
  23.  int main(int argc, char *argv[])
  24.      {
  25.        pthread_t thread;
  26.        thread_args args;
  27.        int status;
  28.        int result;
  29.        int thread_result;
  30.        if (argc < 2) return 1;
  31.        int n = atoi(argv[1]);
  32.        if (n < 30) result = fib(n);
  33.        else {
  34.          args.input = n-1;
  35.          status = pthread_create(thread,
  36.      NULL, thread_func,
  37.      (void*) &args );
  38.         // main can continue executing while the thread executes.
  39.          result = fib(n-2);
  40.         // Wait for the thread to terminate.
  41.          pthread_join(thread, NULL);
  42.          result += args.output;
  43.        }
  44.  printf("Fibonacci of %d is %d./n", n, result);
  45.  return 0;
  46.  }

       注意main里面的if(n<30),当n在30以内时,计算非常快,就不需要使用多线程,当n大于30之后,我们生成一个线程用来计算f(n-1),而main的主线程将继续计算f(n-2),这样等两个线程都结束以后(pthread_join(thread, NULL);),我们将他们的结果相加。

 

      从这个例子就可以看出,自己实现线程的缺点:

        1 这个例子正好可以用两个线程分配在两个核上来实现,可如果一个任务需要16个线程同时执行,我们又不知道客户端到底是几核的CPU时,这个任务如何分配就成为一个问题。

        2 这段代码非常不简洁

        3 额外的结构和函数也破坏了算法本身的完整性。

 

下面我们使用多核支持库来实现该代码:


使用OpenMP

 

  1. int fib(int n) {
  2.   int i, j;
  3.   if (n<2)
  4.      return n;
  5.   else {
  6.     #pragma omp task shared(i)
  7.     i=fib(n-1);
  8.     #pragma omp task shared(j)
  9.     j=fib(n-2);
  10.     #pragma omp taskwait
  11.     return i+j;
  12.   }
  13. }

使用Cilk++

  1. int fib(int n) 
  2. {
  3.   if (n < 2) return n;
  4.  else {
  5.       int x = cilk_spawn fib(n-1);
  6.       int y = fib(n-2);
  7.       cilk_sync;
  8.       return x + y;
  9.      }
  10. }       
  11.                 
  12. int main(int argc, char *argv[])
  13. {       
  14.   int n = atoi(argv[1]);
  15.  int result = fib(n);
  16.  printf("Fibonacci of %d is %d./n", n, result);
  17.  return 0;
  18. }

.NET Task Parallel Library中相应的例子

  1.   Private Function FiboFullParallel(ByVal N As LongAs Long
  2.        If N <= 0 Then Return 0
  3.        If N = 1 Then Return 1
  4.    
  5.        Dim t1 As Tasks.Future(Of Long) = Tasks.Future(Of Long).Create( Function() FiboFullParallel(N - 1))
  6.        Dim t2 As Tasks.Future(Of Long) = Tasks.Future(Of Long).Create( Function() FiboFullParallel(N - 2))
  7.    
  8.        Return t1.Value + t2.Value
  9.    End Function

     可以看到无论使用哪种并发平台,代码都非常简洁,没有破坏原有的算法封装,仅仅通过简单的改造就可以实现自动任务的分派。

 


五、什么情况下该使用多核编程呢?

        如果一个任务的执行时间在10-100毫秒,那么就无需使用多核,因为将任务通过多线程分解到多核上计算,然后再将结果集合起来的开销大致需要100毫秒(当然具体多少依据机器的性能以及你所使用的编译器的性能),而且还需要消耗内存的空间。

        在OpenMP里面我们可以使用"if clause"来给双核配置增加条件,例如下面的代码很明显,当n小于100000的时候,不使用多核,当n大于的时候再使用

  1. #pragma omp parallel for if(n > 100000)
  2. for (i = 0; i < n;, i++) {
  3. ...
  4. }

六、后记

       本文旨在告诉你为何要进行多核开发,以及简单展示了多核开发平台的使用。实际的多核开发要复杂的多,而且我们知道目前的PC机的多核系统都是基于共享内存的,虽然每个核都有自己的一级缓存。因此不同核上的线程在运行时就涉及到对资源竞争使用的问题。除此以外如果应用需要用到IO(硬盘,网络)的时候,也存在同样的问题。因此多核的设计的难点就在于需要具体情况具体分析,找出多核应用的瓶颈,通过改进数据结构或算法,消除或优化这个瓶颈。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: tms320c66x keystone架构多核dsp入门与实例精解.pdf 是一本介绍基于TMS320C66x Keystone架构的多核DSP编程的实践性指南。本书分为四章,每一章都包含了多个实例,逐步深入讲解多核DSP编程的基本概念和实践技巧。 第一章主要介绍Keystone架构的基本特点、硬件资源和多核编程的优势。第二章从单核到多核的转变上做了深入讲解,并且结合实例从基本的多核并行编程开始介绍了TMS320C66x Keystone架构下的Event Manager、Message Manager、Mailbox和RM的使用方法。 第三章介绍了DSP封装的基本操作和解封装方法,同时讲解了运用RTDX技术实现多核DSP互相通讯的方法。第四章讲解了多核DSP异构计算的优越性和实践技巧。通过实例,讲解了提升DSP并行度的四种方法:分割、工作流分配、部署和确定性和非确定性计算。 总体来说,该书是一本聚焦于TMS320C66x Keystone架构下多核DSP编程实践的入门指南和工具手册。需要注意的是,该书对读者在DSP编程方面的基础知识要求较高,建议具备一定的DSP编程经验再进行阅读。 ### 回答2: 《TMS320C66x Keystone架构多核DSP入门与实例精解》是一本介绍Keystone架构多核DSP的入门教材,主要涵盖了Keystone架构、TMS320C66x、多核处理、DSP算法开发、实时系统开发等内容。 Keystone架构是一种高性能、低功耗、灵活可扩展的DSP架构,在嵌入式应用领域得到广泛应用。TMS320C66x是Keystone架构的一种实现,具有高达1.2Tops的处理能力和丰富的片上外设资源。多核处理是Keystone架构的重要特性之一,可以有效提高系统的性能和可靠性。 本书以DSP算法开发为主线,详细介绍了TMS320C66x的架构、资源配置、多核编程、DSP算法开发等方面的内容。同时,还介绍了实时系统开发和性能优化等关键问题,为读者提供了一系列实践案例和经验总结。 本书适合从事嵌入式系统开发、DSP算法开发和实时系统开发等领域的工程师、学生和研究人员阅读。无论是初学者还是有一定经验的开发者,都可以从本书中获得有用的知识和实践经验,提高开发效率和系统性能。 ### 回答3: 《TMS320C66x Keystone架构多核DSP入门与实例精解》是一本介绍Texas Instruments公司TMS320C66x系列多核数字信号处理器的入门教材和实例精解。本书深入浅出地介绍了DSP的体系结构、系统架构、并行编程方法和实现技术等方面的知识,实例详尽而丰富,既全面系统地介绍了该系列DSP的基本概念和特性,又能够从实践出发,提供丰富的应用案例和技术经验。 全书分为十二章,从DSP基础知识讲起,逐渐深入介绍了Keystone系列多核DSP的设计、接口和编程方法等方面的内容。每一章的末尾都有实验项目,让读者听取学到的知识进行实践,深入了解多核DSP的特点和应用。 该书的优点在于深入浅出,易于理解。同时,该书的实例很丰富,从任务调度、矩阵乘法、FFT算法、卷积编码等实例都贴近实际,体现了多核DSP的应用价值。该书对于学习多核DSP的学生、工程师、技术人员都是很好的参考材料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值