我可以在python中为计算密集型任务应用多线程吗?
更新:为了节省您的时间,我在这里直接给出答案。如果您使用纯Python编写代码,Python不能同时利用多cpu核。但是当Python调用一些用C编写的函数或包时,比如Numpy等,它可以同时利用多核我可以在python中为计算密集型任务应用多线程吗?,python,multithreading,cpython,gil,Python,Multithreading,Cpython,Gil,更新:为了节省您的时间,我在这里直接给出答案。如果您使用纯Python编写代码,Python不能同时利用多cpu核。但是当Python调用一些用C编写的函数或包时,比如Numpy等,它可以同时利用多核 我听说“python中的多线程不是真正的多线程,因为GIL”。我还听说,“python多线程可以处理IO密集型任务,而不是计算密集型任务,因为同一时间只有一个线程运行。” 但我的经历让我重新思考这个问题。我的经验表明,即使对于计算密集型任务,python多线程也几乎可以明显加快计算速度。(在多线
我听说“python中的多线程不是真正的多线程,因为GIL”。我还听说,“python多线程可以处理IO密集型任务,而不是计算密集型任务,因为同一时间只有一个线程运行。” 但我的经历让我重新思考这个问题。我的经验表明,即使对于计算密集型任务,python多线程也几乎可以明显加快计算速度。(在多线程处理之前,运行以下程序需要300秒,在使用多线程处理之后,需要100秒。) 下图显示了5个线程是由
python
和CPython
作为带包threading
的编译器创建的,并且所有cpu核的比例接近100%
我认为屏幕截图可以证明5个cpu内核同时运行
有人能给我解释一下吗?我可以在python中为计算密集型任务应用多线程吗?或者可以在python中同时运行多线程/内核
我的代码:
import threading
import time
import numpy as np
from scipy import interpolate
number_list = list(range(10))
def image_interpolation():
while True:
number = None
with threading.Lock():
if len(number_list):
number = number_list.pop()
if number is not None:
# Make a fake image - you can use yours.
image = np.ones((20000, 20000))
# Make your orig array (skipping the extra dimensions).
orig = np.random.rand(12800, 16000)
# Make its coordinates; x is horizontal.
x = np.linspace(0, image.shape[1], orig.shape[1])
y = np.linspace(0, image.shape[0], orig.shape[0])
# Make the interpolator function.
f = interpolate.interp2d(x, y, orig, kind='linear')
else:
return 1
workers=5
thd_list = []
t1 = time.time()
for i in range(workers):
thd = threading.Thread(target=image_interpolation)
thd.start()
thd_list.append(thd)
for thd in thd_list:
thd.join()
t2 = time.time()
print("total time cost with multithreading: " + str(t2-t1))
number_list = list(range(10))
for i in range(10):
image_interpolation()
t3 = time.time()
print("total time cost without multithreading: " + str(t3-t2))
输出为:
total time cost with multithreading: 112.71922039985657
total time cost without multithreading: 328.45561170578003
多线程期间top
的屏幕截图
多线程期间top-H
的屏幕截图
top
的屏幕截图,然后按1
在多线程期间
不带多线程的top-H的屏幕截图
Python线程是一种真正的线程,只是解释器中不能同时有两个线程(这就是GIL的意义所在)。代码的本机部分可以很好地并行运行,而不会在多个线程上发生争用,只有在返回到解释器时,它们必须在彼此之间进行序列化
事实上,您的所有CPU内核都已加载到100%,这并不能证明您正在“有效地”使用该机器。您需要确保CPU的使用不是由于上下文切换造成的
如果您切换到多处理而不是线程(它们非常相似),您不必重复猜测,但在线程之间传递时,您必须封送负载
所以无论如何都需要测量所有内容。正如您所提到的,Python有一个“全局解释器锁”(GIL),它防止两个Python代码线程同时运行。多线程可以加速IO绑定任务的原因是Python在监听网络套接字或等待磁盘读取时释放GIL。因此GIL不会阻止计算机同时执行两个大量的工作,它会阻止同一个Python进程中的两个Python线程同时运行
在您的示例中,使用numpy和scipy。这些主要是用C编写的,并使用C/Fortran/Assembly编写的库(BLAS、LAPACK等)。在numpy阵列上执行操作时,类似于在该阵列中侦听套接字。当GIL被释放并且numpy数组操作被调用时,numpy将决定如何执行该工作。如果需要,它可以生成其他线程或进程,它调用的BLAS子例程可能会生成其他线程。如果您想从源代码编译numpy,那么可以在构建时配置是否/如何完成这项工作
总之,你发现了一个例外。如果您仅使用纯Python函数重复此实验,您将得到完全不同的结果(例如,请参阅上面链接的页面的“比较”部分)。您使用了什么代码进行测试?如果它们都有不同的PID,那么您可能是无意中使用了多处理。@FiddleStix Ya,我对此感到奇怪。另外,509 total,508 sleeping
表明没有进行任何实际工作。@FiddleStix我使用python中的线程包,因此我认为我没有使用多处理。@Carcigenicate我认为509 total,508 sleeping
没有提供任何关于运行线程数的信息。这意味着任务号或进程号。你的意思是,如果我使用的是用C编写的包中的函数,那么多线程可以同时运行吗。但是如果我只使用纯python构建的函数,那么多线程就不能同时运行。对吧?没错。我不确定Python解释器是自动释放GIL,还是C代码(在本例中是numpy)必须显式释放GIL。换句话说,我不确定它是否适用于所有从Python调用的C代码,这可能取决于具体情况。