2014-09-11 91 views
8

我在網絡服務器(apache + modwsgi + django)上使用pandas,並且有一個難以複製的bug,現在我發現它是由不是線程安全的熊貓引起的。熊貓和numpy線程安全

經過大量的代碼縮減後,我終於找到了一個簡短的獨立程序,可以用來重現問題。你可以在下面看到它。

重點是:與this question的回答相反,這個例子表明即使非常簡單的操作不會修改數據幀,熊貓也會崩潰。我無法想象這個簡單的代碼片斷如何可能與線程不安全...

問題是關於在網絡服務器中使用熊貓和numpy。可能嗎?我應該如何使用熊貓來修復我的代碼? (鎖的使用的一個例子將是有益的)

這裏是使段錯誤的代碼:

import threading 
import pandas as pd 
import numpy as np 

def let_crash(crash=True): 
    t = 0.02 * np.arange(100000) # ok con 10000                    
    data = pd.DataFrame({'t': t}) 
    if crash: 
     data['t'] * 1.5 # CRASH 
    else: 
     data['t'].values * 1.5 # THIS IS OK! 

if __name__ == '__main__': 
     threads = [] 
     for i in range(100): 
      if True: # asynchronous                       
       t = threading.Thread(target=let_crash, args =()) 
       t.daemon = True 
       t.start() 
       threads.append(t) 
      else: # synchronous                        
       let_crash() 
     for t in threads: 
      t.join() 

我的環境:蟒2.7.3,1.8.0 numpy的,熊貓0.13.1

+1

不會爲我崩潰。 Python 2.7.6,numpy 1.8.2,熊貓0.14.1。我嘗試了主循環,直到「10000」。 – osa 2014-09-24 04:22:50

回答

3

請參閱此處的文檔中的警告:http://pandas.pydata.org/pandas-docs/dev/gotchas.html#thread-safety

熊貓不是線程安全的,因爲底層的複製機制不是。 Numpy我相信有一個原子複製操作,但熊貓有一個層以上。

複製是大熊貓操作的基礎(如大多數操作產生一個新的對象返回給用戶)

這是不平凡的解決這一問題,並會拿出一個相當沉重的PERF的成本因此將需要一點點正確處理這一問題的工作。

最簡單的就是不要在線程之間共享對象或將它們鎖定在使用狀態。

+1

但是沒有任何對象被共享,他的DataFrame對於每個線程來說都是本地的......這看起來和[this]非常相似(https://github.com/numpy/numpy/issues/4642),並且解決方案應該是關於釋放GIL更加小心,請參閱[這裏](https://github.com/numpy/numpy/pull/4648)。你確定你沒有在需要調用Python API函數的地方發佈GIL嗎? – Jaime 2014-09-11 11:20:52

+0

nope - 這些都涉及numpy/Numexpr(這裏沒有涉及c或cython代碼)所以可能會出現問題 – Jeff 2014-09-11 12:11:21

+0

實際上,它們涉及一些cython代碼,但在列訪問中。數據['t']''用於各種類型的檢查/索引。應該是線程安全的。 – Jeff 2014-09-11 12:23:35

0

將mod_wsgi配置爲在單線程模式下運行。

WSGIDaemonProcess mysite processes=5 threads=1 
WSGIProcessGroup mysite 
WSGIApplicationGroup %{GLOBAL} 

在這種情況下,它使用的mod_wsgi daemon模式,這樣的進程/線程可以獨立於你使用任何的Apache MPM進行設置。

+0

我已經試過這個解決方案,但是線程數= 1會讓一些請求需要很長時間才能掛起。 – 2014-09-12 19:57:09

+1

進程在這種情況下提供了併發性,爲什麼你有多個進程。您實際指定了多少個進程?請求的平均運行時間是多少?吞吐量是多少?您需要了解這些才能正確提供足夠的容量。如果只有特定的URL在多線程中遇到了這個問題,那麼您可以在多個mod_wsgi守護進程組中將應用程序垂直分區,並將不安全的URL保存在單線程進程中。看到下面的帖子:http://blog.dscpl.com.au/2014/02/vertically-partitioning-python-web.html – 2014-09-12 20:24:01

+0

這很有趣。我確信threads = 1是不對的......我不知道在哪裏尋找進程的數量,我有apache的默認配置。但是pstree告訴我有很多(超過100)。問題在於文件上傳...當客戶端啓動文件上傳(可能需要幾分鐘)時,服務器變得無法響應。我認爲與postgresql事務有關聯,並試圖使用手動提交等類似的東西,但沒有成功。 – 2014-09-13 06:08:25