Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我可以在python中为计算密集型任务应用多线程吗?_Python_Multithreading_Cpython_Gil - Fatal编程技术网

我可以在python中为计算密集型任务应用多线程吗?

我可以在python中为计算密集型任务应用多线程吗?,python,multithreading,cpython,gil,Python,Multithreading,Cpython,Gil,更新:为了节省您的时间,我在这里直接给出答案。如果您使用纯Python编写代码,Python不能同时利用多cpu核。但是当Python调用一些用C编写的函数或包时,比如Numpy等,它可以同时利用多核 我听说“python中的多线程不是真正的多线程,因为GIL”。我还听说,“python多线程可以处理IO密集型任务,而不是计算密集型任务,因为同一时间只有一个线程运行。” 但我的经历让我重新思考这个问题。我的经验表明,即使对于计算密集型任务,python多线程也几乎可以明显加快计算速度。(在多线

更新:为了节省您的时间,我在这里直接给出答案。如果您使用纯Python编写代码,Python不能同时利用多cpu核。但是当Python调用一些用C编写的函数或包时,比如Numpy等,它可以同时利用多核


我听说“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代码,这可能取决于具体情况。