2012-06-28 49 views
2

我第一次在生產代碼觀察這個問題,然後做了一個原型:Python的多線程代碼是慢於單線程

import threading, Queue, time, sys 

def heavyfunc(): 
    ''' The idea is just to load CPU ''' 
    sm = 0 
    for i in range(5000): 
     for j in range(5000): 
      if i + j % 2 == 0: 
       sm += i - j 
    print "sm = %d" % sm 

def worker(queue): 
    ''' worker thread ''' 
    while True: 
     elem = queue.get() 
     if elem == None: break 
     heavyfunc()   # whatever the elem is 


starttime = time.time() 

q = Queue.Queue()    # queue with tasks 

number_of_threads = 1 
# create & start number_of_threads working threads 
threads = [threading.Thread(target=worker, args=[q]) for thread_idx in range(number_of_threads)] 
for t in threads: t.start() 

# add 2 working items: they are estimated to be computed in parallel 
for x in range(2): 
    q.put(1) 

for t in threads: q.put(None) # Add 2 'None' => each worker will exit when gets them 
for t in threads: t.join() # Wait for every worker 

#heavyfunc() 

elapsed = time.time() - starttime 

print >> sys.stderr, elapsed 

heavyfunc的想法()僅僅是加載CPU,沒有任何同步和依賴。

當使用1個線程,需要4.14秒中平均 當使用2個線程,它在不使用任何線程,以計算heavyfunc()採用6.40秒中平均 取2.07秒的平均(測定多次,這是正好是4.14/2,就像1個線程和2個任務一樣)。

我在等2個線程期望2個帶有heavyfunc()的作業需要2.07秒。 (我的CPU是i7 =>有足夠的核心)。

這裏是CPU顯示器的屏幕截圖也給有沒有真正的多線程的想法:

CPU Load Graphi

哪裏是在我的思想的錯誤?如何創建不干擾的n個線程?

+1

正如在線程模塊的文檔開始的相當大的筆記所說.. CPython中只有一個線程,使用進程。 – Voo

+0

這是衆所周知的Python行爲,請參閱[瞭解Python GIL](http://www.dabeaz.com/GIL/)。 –

+0

另請參閱多進程模塊。 –

回答

4

CPython不會在一個以上的內核上執行字節碼。多線程cpu綁定代碼毫無意義。全局解釋器鎖(GIL)用於保護進程中的所有引用計數,因此一次只能有一個線程使用Python對象。

您看到的性能更差,因爲您一次只工作一個線程,但現在您還在更改線程上下文。

+0

在這種情況下,從線程切換到多處理可能會很有用。就像我看到的那樣,Python似乎很好地利用線程來處理不是CPU密集型的任務,但是這可能會由於其他原因(通常是I/O,比如對Web請求的請求)而放慢代碼。如果我們有CPU密集型任務將您的機器推到極限,多處理可能會打開另一扇門,讓您可以同時完成更多工作。 –