我最近在python中了解了GIL。 我做了一些基准测试,发现多线程确实提高了性能。我比较了不使用任何内部多线程的elementwise NumPy操作。在第一个测试中,我从for循环顺序调用函数32次。在第二种情况下,我使用多线程。但是如果GIL正在工作,在第二种情况下,一次只能有一个线程处于活动状态,因此执行时间应该大致相等(由于多线程开销,在第二种情况下更糟)。这不是我观察到的
import os
import threading
import numpy as np, time
def elemntwiseoperations(a,b):
np.exp(a)+np.sin(b)
N=1024
a=np.random.rand(N,N)
b=np.random.rand(N,N)
NoTasks=32
start_time = time.time()
for i in range(NoTasks):
elemntwiseoperations(a,b)
print("Execution time for {} tasks: {} seconds, {} seconds per task".format(NoTasks,time.time() - start_time,(time.time() - start_time)/NoTasks))
threads=[]
start_time = time.time()
for i in range(NoTasks):
x = threading.Thread(target=elemntwiseoperations,name=''.format(i),args=(a,b))
x.start()
threads.append(x)
for process in threads:
process.join()
print("Execution time for {} tasks: {} seconds, {} seconds per task".format(NoTasks,time.time() - start_time,(time.time() - start_time)/NoTasks))
输出:
Execution time for 32 tasks: 0.5654711723327637 seconds, 0.01767103374004364 seconds per task
Execution time for 32 tasks: 0.17153215408325195 seconds, 0.005360409617424011 seconds per task
MacOS,Python3.7.6,Cpython实现
因此,我目前的最佳猜测如下: 在第一种情况下,一个线程按顺序启动C例程。它会等待每一个任务完成,然后再开始新的任务。因为我只使用了在numpy中没有并行化的元素操作,所以在整个过程中只使用了一个线程
在第二种情况下,我调用32个虚拟线程,每个线程都受GIL的影响。第一个线程启动C例程并将GIL控制权交给第二个线程,然后第二个线程启动C例程并将控制权交给第三个线程,依此类推。尽管不同时调用C例程,但它们都是并发执行的,因为C不受GIL的影响
我不知道如何实际检查它,但在阅读了几篇关于GIL的python博客后,我就是这样理解它的
相关问题 更多 >
编程相关推荐