2017-07-06 90 views
-4

时间采取的顺序代码(seq.py为什么GIL不允许执行线程代码?

import time 

def countDown(n): 
    while n > 0: 
     n -= 1 

n = 50000000 
start = time.time() 
countDown(n) 
end = time.time() 
print(end-start) 

是,

$ python3.6 seq.py 
4.209718227386475 
$ python3.6 seq.py 
4.007786750793457 
$ python3.6 seq.py 
4.0265843868255615 
$ 

采取螺纹版本(usingThreads.py)时间,

from threading import Thread 
import time 
def countDown(n): 
    while n > 0: 
     n -= 1 


n = 50000000 

t1 = Thread(target=countDown, args=(n//2,)) 
t1.daemon = True 
t2 = Thread(target=countDown, args=(n//2,)) 
t2.daemon = True 

start = time.time() 
t1.start() 
t2.start() 
t1.join() 
t2.join() 
end = time.time() 
print(end-start) 

是,

$ python3.6 usingThreads.py 
4.1083903312683105 
$ python3.6 usingThreads.py 
4.093154668807983 
$ python3.6 usingThreads.py 
4.092989921569824 
$ python3.6 usingThreads.py 
4.116031885147095 
$ 

$ nproc 
4 
$ 

Python解释器不应该允许CPU绑定线程释放GIL。

期待usingThreads.py采取更多的执行时间比seq.py,因为,

1)任何一个线程在时间执行,尽管4个内核

2)取为失败的尝试时间从线程1获取GIL通过thread2(反之亦然)应该延迟执行。

编辑:

随着n=500000000

$ python3.6 seq.py 
40.22602105140686 
$ python3.6 seq.py 
40.510098457336426 
$ python3.6 seq.py 
40.04688620567322 
$ 
$ python3.6 usingThreads.py 
40.91394829750061 
$ python3.6 usingThreads.py 
42.30081081390381 
$ python3.6 usingThreads.py 
41.328694581985474 

问:

为什么比seq.py更好usingThread.py执行?

+0

在我看来就像使用线程通常是越慢,seq.py次仅快于一个。 – barny

+0

我怀疑这是因为你在线程版本中使用了'join()',这可能消除了通常与使用线程相关的大部分开销。 – martineau

+0

@martineau这是我知道等待线程完成的唯一途径,然后计算完成工作所需的时间。如何避免'join()'? – overexchange

回答

0

代码的两个版本做相同的工作数量,所以它几乎花同样的时间量(计数5000倍)。

的吉尔使得它如此他们不会并行运行(这样的线程版本不是更快),但是从上下文切换的开销是relativly小,所以你得到了几乎相同的结果。

这里有个解释http://www.dabeaz.com/python/UnderstandingGIL.pdf

他使用相同的例子,你,并在此演示文稿,他得到了时,他使用一台计算机与超过1个CPU的速度较慢线程版本,他说不错不错当你使用超过1个CPU,你会得到更多的开销(更多的尝试,以上下文切换)巫婆让你的程序慢

+0

线程版本较慢? python3.6线程执行得更好 – overexchange

+0

只有第一个seq.py运行比使用线程慢,另外两个更快。你需要一个更大的样本才能更清晰。 – barny

+0

运行中'seq.py'的平均时间为'4.081363121668498',线程的平均时间为'4.102641701698303' – DorElias