首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用发布的GIL和复杂线程的多线程代码在Python中速度较慢

使用发布的GIL和复杂线程的多线程代码在Python中速度较慢
EN

Stack Overflow用户
提问于 2018-06-20 07:54:23
回答 1查看 464关注 0票数 1

我在一台8核处理器的机器上工作,使用的是8G内存和Linux Redhat 7,我使用的是Pycharm IDE。

我尝试使用python线程模块来利用多核处理的优势,但最终得到的代码要慢得多。我通过Numba发布了GIL,并确保我的线程正在进行足够复杂的计算,因此问题不是在例如How to make numba @jit use all cpu cores (parallelize numba @jit)中讨论的问题

下面是多线程代码:

代码语言:javascript
复制
l=200

@nb.jit('void(f8[:],f8,i4,f8[:])',nopython=True,nogil=True)
def force(r,ri,i,F):

   sum=0
   for j in range(12):
       if (j != i):
           fij=-4 * (12*1**12/(r[j]-ri)**13-6*1**6/(r[j]-ri)**7)
           sum=sum+fij

   F[i+12]=sum

def ODEfunction(r, t):

   f = np.zeros(2 * 12)

   lbound=-4* (12*1**12/(-0.5*l-r[0])**13-6*1**6/(-0.5*l-r[0])**7)
   rbound=-4* (12*1**12/(0.5*l-r[12-1])**13-6*1**6/(0.5*l-r[12-1])**7)

   f[0:12]=r[12:2*12]

   thlist=[threading.Thread(target=force, args=(r,r[i],i,f)) for i in range(12)]

   for thread in thlist:
       thread.start()
   for thread in thlist:
       thread.join()

   f[12]=f[12]+lbound
   f[2*12-1]=f[2*12-1]+rbound
   return f

这是顺序版本:

代码语言:javascript
复制
l=200

@nb.autojit()
def ODEfunction(r, t):

   f = np.zeros(2 * 12)
   lbound=-4* (12*1**12/(-0.5*l-r[0])**13-6*1**6/(-0.5*l-r[0])**7)
   rbound=-4* (12*1**12/(0.5*l-r[12-1])**13-6*1**6/(0.5*l-r[12-1])**7)

   f[0:12]=r[12:2*12]

   for i in range(12):
       fi = 0.0
       for j in range(12):
           if (j!=i):
               fij = -4 * (12*1**12/(r[j]-r[i])**13-6*1**6/(r[j]-r[i])**7)
               fi = fi + fij
       f[i+12]=fi
   f[12]=f[12]+lbound
   f[2*12-1]=f[2*12-1]+rbound
   return f

我还想在多线程和顺序代码运行期间附加一个系统监视器的图像:

System Motinor during the run of the multi threaded code

System Motinor during the run of the sequential code

有人知道线程化代码效率低下的原因是什么吗?

EN

回答 1

Stack Overflow用户

发布于 2018-06-21 00:31:17

你必须意识到,在Python中调用一个函数是非常昂贵的(例如,与在C中调用一个函数相比),甚至调用一个numba-jitted函数:必须检查参数是否正确(例如,它们确实是你正在传递的浮点数组-我们将看到它可能比普通的Python调用慢5倍)。

让我们来检查一下Let函数的开销,与函数中发生的工作相比:

代码语言:javascript
复制
import numba as nb
import numpy as np

@nb.jit('void(f8[:],f8,i4,f8[:])',nopython=True,nogil=True)
def force(r,ri,i,F):

   sum=0
   for j in range(12):
       if (j != i):
           fij=-4 * (12*1**12/(r[j]-ri)**13-6*1**6/(r[j]-ri)**7)
           sum=sum+fij

   F[i+12]=sum

@nb.jit('void(f8[:],f8,i4,f8[:])',nopython=True,nogil=True)
def nothing(r,ri,i,F):
    pass

def no_jit(r,ri,i,F):
    pass

F=np.zeros(24)
r=np.zeros(12)

现在:

代码语言:javascript
复制
>>>%timeit force(r,1.0,0,F)
706 ns ± 8.96 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>>%timeit nothing(r,1.0,0,F)
645 ns ± 5.36 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
>>>%timeit no_jit(r,1.0,0,F) #to measure overhead of numba
120 ns ± 6.56 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

所以基本上有90%的开销,这在单线程模式下是没有的,因为函数是“内联”的。这并不奇怪:您的for循环只有12次迭代-这是不够的,例如,在示例中,您链接的内部循环有10^10迭代!

此外,在线程之间分派工作也会产生一些开销,我的直觉是它甚至比jitted call的开销还要多-但为了确保人们应该分析程序。即使有8个内核,这些赔率也很难被击败!

与花费在函数本身上的时间相比,现在最大的拦路虎可能是force-call的巨大开销。上面的分析非常肤浅,所以我不能保证没有其他重要的问题--但让force有更多的工作将是朝着正确方向迈出的一步。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50938382

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档