西西河

主题:【求助】:请教信息技术方面的大牛有关多线程的问题 -- newtime

共:💬51 🌺45 新:
分页树展主题 · 全看首页 上页
/ 4
下页 末页
  • 家园 【求助】:请教信息技术方面的大牛有关多线程的问题

    请教为何多线程执行起来花费时间比单线程要多呢?

    非常感谢!!!

    问题如下:

    函数是用MONT CARLO方法计算圆周率。单线程计算函数两次共耗费大约是97s;而两个线程分别计算函数一次耗费的时间是392s.

    环境:

    CPU: i7920 4核

    内存:3GB

    操作系统:Windows Vista

    编译器:Intel Fortran 90

    程序如下:

    多线程主程序:

    Program TESTPROC0

    use ifmt

    use threadfunction

    implicit none

    integer,parameter::n_thread=2,n_c=2

    integer(INT_PTR_KIND())::Threads_Handle(n_thread),waitresult,cend,retlog,retint,&

    thread_handle_1,thread_handle_2

    integer(INT_PTR_KIND()), PARAMETER :: security = 0

    integer(INT_PTR_KIND()), PARAMETER :: stack_size = 0

    integer(INT_PTR_KIND()) :: thread_id,rc

    integer(4)::i,slot

    real(kind(1d0))::pi,time_begin,time_end,t0,t1

    call cpu_time(time_begin)

    slot=0

    Thread_Handle_1= CreateThread(security,stack_size,Thread_Proc0,loc(i), 0, thread_id)

    Thread_Handle_2=CreateThread(security,stack_size,Thread_Proc0,loc(i), 0, thread_id)

    waitresult=waitforsingleobject(thread_handle_1,infinite)

    waitresult=waitforsingleobject(thread_handle_2,infinite)

    cend=closehandle(thread_handle_1)

    cend=closehandle(thread_handle_2)

    call cpu_time(time_end)

    t1=time_end-time_begin

    write(6,*) "multithread computation takes time",t1,t1/n_c

    pause

    end program TESTPROC0

    单线程主程序:

    Program TESTPROC0

    use threadfunction

    implicit none

    integer,parameter::n_c=2

    integer(INT_PTR_KIND()) :: thread_id,rc

    integer(4)::i,slot

    real(kind(1d0))::pi,time_begin,time_end,t0,t1

    call cpu_time(time_begin)

    do i=1,n_c

    pi=Thread_Proc0(i)

    enddo

    call cpu_time(time_end)

    t0=time_end-time_begin

    write(6,*) "computation takes time",t0,t0/n_c

    pause

    end program TESTPROC0

    函数:

    Module threadfunction

    contains

    real(kind(1d0)) function Thread_Proc0(arg) implicit none

    !DEC$ ATTRIBUTES STDCALL, ALIAS:"_thread_proc0" :: Thread_Proc0

    integer(4),intent(in):: arg

    integer(4),parameter::j=999999999

    integer(4)::i

    real(kind(1d0))::x,y,u,q

    q=0

    do i=1,j

    call random_number(x)

    call random_number(y)

    u=x**2.0d0+y**2.0d0

    if (u<1.0d0) then

    q=q+1.0d0

    endif

    enddo

    Thread_proc0=q/j*4

    end function Thread_Proc0

    end Module threadfunction

    关键词(Tags): #多线程
    • 家园 问题已经解决

      要感谢各位热心筒子的帮助,尤其是autoeagle,给出了很多的解释和信息。:)

      这个问题已经解决。总结一下

      1 random_number函数不适合用多线程计算

      2 需要disable bios 上的 hthread 和 turbo mode

      现在四线程所费的时间已经非常接近于一线程的四分之一。

      我用的是openmp。

      • 家园 祝贺一下

        另外提醒,你的问题基本没有通信,规模也小,用OpenMP还行,复杂点的还是要用MPI。当年我用MPI+openMP+SSE2共同优化,同样的机器效率提升180%,非常自豪喔

    • 家园 关于并行计算的一些基本概念的回忆

      两年没碰并行计算了,我当年还是下过一些功夫,靠这个混到学位了。

      1、线程、进程的区别

      简单的说,就是线程间共享内存地址空间,可以直接进行数据交换,而进程不共享内存地址空间,需通过进程间通信进行数据交换。

      咋一看,多线程模式数据交换更方便、直接,但事实上,对于计算密集型的并行计算而言,多进程效率远高于多线程。其根本原因是缓存的影响。

      多级缓存结构是冯诺依曼以来,计算机体系结构的最大进步,解决了运算器的高速要求和存储器的大容量要求的矛盾,通过小而快的寄存器、一级缓存、二级缓冲,到大而慢的内存、外存的分级处理,大大提高了运算效率。一般而言,计算密集型程序读写内存的指令数在4%左右,内存延迟一般在100时钟周期以上,计算机体系架构和编译器优化效果的关键,就在对读写内存的指令数的处理上。

      多线程程序的最大问题,就是将各线程间缓存的处理交给了操作系统,用线程池等方法进行分配,而操作系统并不清楚程序员的实际意图,所以效率一般不高。而多进程程序各进程之间不会相互干扰,需要进行信息传递的数据由程序员显式指定,亲自设计通信方法,有利于针对缓存的优化。

      究其根本,多线程程序的起源,是在单个CPU上满足多个用户的非计算密集型需求,只要延迟小于几秒,用户的体验不会受到影响,采用多线程编程,可以很容易的写出满足多用户业务操作的商业应用系统。而对于计算密集型任务,常用高效的处理方法是批处理。

      简而言之,多线程程序不适合采用目前的多级缓存、多核处理器体系架构下设计计算密集型程序。事实上,OpenMP这套东西效果也很差,因为其前身MPP机器的缓存结构,与MPI所针对的集群结构相比,也是非常简单的,目前的多核机器的缓存结构,更适合于MPI。

      • 家园 多线程多进程的优劣不可一概而论

        基本上取决于系统的实现方式。一般来说,多线程都在一个地址空间,可以少用系统支持,限制少,比较方便,但容易出bug。

      • 家园 有什么并行计算baby level的书推荐么?谢谢啊
      • 家园 多线程这玩意纯粹是微软推广出来的

        看起来很美,其实还不如多进程

      • 家园 【求助】

        对于计算密集型问题,在多核上多进程才是更加合适的吗?按照您的指导,我用多进程试试。

        • 家园 你还没理解

          一人能扛一袋100斤的大米,你让他扛2袋每袋60斤的大米,你说他能扛动吗?

          科学计算本质上与听音乐、放视频等是不同的,通常一个进程、线程就能把CPU占满,根本不用多进程、多线程提高单CPU上的效率。相反,在单CPU上多线程、多进程反而会降低效率。

          autoeagle说的多进程,通常是指多台机器上运行的,最差也是一台机器上多路CPU上运行的。

          至于多核CPU,目前对科学计算没戏,因为它没解决内存访问的瓶颈。

          同理,我非常怀疑CUDA架构的有效性,因为它好象也没有解决内存访问的瓶颈。

          • 家园 多核CPU对科学计算支持的很好

            目前的多核机,其巨大的多级缓存是独立的,所以基本解决了内存访问瓶颈,但前提是各计算区域的相对独立性。一般而言,运行多进程程序,多核效果比多路好,多路效果比多机好,毕竟内部通信效率要比外部高。 你所说的,应该是超线程技术在科学计算中的应用不良,这就是因为超线程技术依靠的是一条运算流水线上的两套处理单元,但没有设立独立缓存和寄存器的结果。不过SSE技术用好了,可以明显提高科学计算效率。 GPU计算的结构比较接近于当年的MPP,大规模并行机,而且缓存结构更加简单,只有对那些进程通信非常少的大规模计算程序,如地震资料解析,多路流媒体处理,视频图像处理等方面效果好,其实其本来也是做事情的。

            • 家园 请教:老兄看这个问题如何优化

              我通常解的二维问题:

              网格是1024*1024,这样是1M个节点,一个节点要5个变量,一个变量8个字节(double)。这样一个稀疏矩阵存储至少要40M。解这个线性方程组,就是不断读这个40M的数组的过程。但问题是Cache不可能放下这个数组。

              所以,在一个CPU或双路CPU上,我认为是没法解决的。

              老兄有何高见?

              • 家园 我还遇到过jvm把内存吃光的事情

                给了-X都不行,当时是要验证自己写的算法的有效性。后来的解决办法是:不用jvm提供的基本对象,因为java.lang.Object在一般的实现里面,每个对象有8个byte的overhead,只能自己用大数组去存每个实例的一个属性,这样每个数组有这个overhead,而不是每个对象都浪费 8 bytes。

                除了autoeagle的建议以外,我建议你去看看你的程序是否有某种访存模式。我隐约记得解方程组的时候,访存通常是逐行/逐列,最多是按对角线来。这样的话,你可以安排数据在内存里面的排列顺序,CPU会按cache line来读取数据,如果你的数据安排合适,每个cache line的第一个数据读过以后,后面的数据也在cache里面了。

                或者你自己去添一两句汇编,prefetch一下后面一个循环要用的数据。

              • 家园 有时间的话,推荐看看《计算机程序设计艺术》这套巨著

                缓存装不下真是小问题了。当年科学家们遇到的问题是内存装不下,如何改进算法,减少读硬盘的问题。更早之前,是硬盘都装不下,如何改进算法,减少读磁带的问题。这些问题的解答,都在那套书里。

分页树展主题 · 全看首页 上页
/ 4
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河