7

我正在開發一個使用python 2.7的gae上的應用程序,ajax調用從API請求一些數據,一個請求可能需要〜200 ms,但是當我打開兩個瀏覽器並使兩個請求在非常接近的時間他們採取比這更多的雙倍,我已經嘗試了所有的線程,但它沒有工作..(這發生在應用程序在線時,不僅在開發服務器上)Python中的並行性不能正常工作

所以我寫了這個簡單的測試,看看這是一般蟒蛇的問題(在忙等待的情況下),這裏是代碼和結果:

def work(): 
    t = datetime.now() 
    print threading.currentThread(), t 
    i = 0 
    while i < 100000000: 
     i+=1 
    t2 = datetime.now() 
    print threading.currentThread(), t2, t2-t 

if __name__ == '__main__': 
    print "single threaded:" 
    t1 = threading.Thread(target=work) 
    t1.start() 
    t1.join() 

    print "multi threaded:" 
    t1 = threading.Thread(target=work) 
    t1.start() 
    t2 = threading.Thread(target=work) 
    t2.start() 
    t1.join() 
    t2.join() 

在Mac OS X的結果, C礦石i7(4核心,8線程),python2.7:

single threaded: 
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:07.763146 
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:13.091614 0:00:05.328468 

multi threaded: 
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:13.091952 
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:13.102250 
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:29.221050 0:00:16.118800 
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:29.237512 0:00:16.145560 

這是非常令人震驚!如果一個線程需要5秒鐘才能做到這一點..我認爲同時啓動兩個線程將花費相同的時間來完成這兩個任務,但它需要幾乎三倍的時間..這使得整個線程的想法無用,因爲順序執行它們會更快!

缺少什麼我在這裏..

+3

你有沒有讀過任何有關Python中的全局解釋器鎖(GIL)?如果你想要並行處理,你應該看看多處理,而不是線程。一次執行僅限於一個線程,除非您正在使用的庫專門用於釋放GIL。 –

+2

你的基準設計不佳。您的實際使用案例將受IO限制,而不受CPU限制。 Python的GIL在每種情況下的行爲都大相徑庭。線程*應該*在您的真實用例中可以正常工作。 – zeekay

+1

@ g.d.d.c。多處理在GAE中不可用 – bpgergo

回答

9

David Beazley gave a talk約在2010年PYCON 這個問題,因爲其他人已經指出,對於某些任務,尤其是使用多核線程可能會導致比單個線程執行相同的任務性能較低。這個問題,比茲利發現,有與具有"GIL battle"多個內核做:

enter image description here

爲了避免GIL爭,你可能會得到具有獨立的過程,而不是單獨的線程運行的任務更好的結果。 multiprocessing模塊提供了一種方便的方法來實現這一點,特別是因爲多處理API與線程API非常相似。

import multiprocessing as mp 
import datetime as dt 
def work(): 
    t = dt.datetime.now() 
    print mp.current_process().name, t 
    i = 0 
    while i < 100000000: 
     i+=1 
    t2 = dt.datetime.now() 
    print mp.current_process().name, t2, t2-t 

if __name__ == '__main__': 
    print "single process:" 
    t1 = mp.Process(target=work) 
    t1.start() 
    t1.join() 

    print "multi process:" 
    t1 = mp.Process(target=work) 
    t1.start() 
    t2 = mp.Process(target=work) 
    t2.start() 
    t1.join() 
    t2.join() 

產生

single process: 
Process-1 2011-12-06 12:34:20.611526 
Process-1 2011-12-06 12:34:28.494831 0:00:07.883305 
multi process: 
Process-3 2011-12-06 12:34:28.497895 
Process-2 2011-12-06 12:34:28.503433 
Process-2 2011-12-06 12:34:36.458354 0:00:07.954921 
Process-3 2011-12-06 12:34:36.546656 0:00:08.048761 

PS。正如zeekay在評論中指出的那樣,GIL戰鬥對於CPU限制任務來說只是非常嚴重的。它不應該是一個IO綁定任務的問題。

+0

此行爲是否特定於Python?如果是這樣,爲什麼? –

+1

GIL特定於Python,因此「GIL戰鬥」特定於GIL。我不確定在其他語言中是否會出現類似的情況。 – unutbu

1

我想看看那裏的時候是怎麼回事。例如,假設服務器每200毫秒只能回答一個查詢。然後就沒有什麼可以做的了,每200毫秒只能得到一個回覆​​,因爲這是服務器可以提供給你的。

+0

看看他的代碼。他正在調用'datetime',不與服務器通信。 –