2014-09-11 7 views
8

웹 서버 (apache + modwsgi + django)에서 pandas을 사용하고 있으며, 판다가 스레드로부터 안전하지 않아서 발견 된 버그를 재현하기가 어렵습니다.팬더와 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, NumPy와 1.8.0, 팬더 0.13.1

다음

이 분할 오류를 일으키는 코드 (잠금 사용의 예 도움이 될 것입니다)
+1

나를 위해 충돌하지 않습니다. Python 2.7.6, numpy 1.8.2, pandas 0.14.1. 나는 '10000'까지 메인 루프를 시도했다. – osa

답변

3

여기에있는 문서의주의 사항을 참조하십시오. http://pandas.pydata.org/pandas-docs/dev/gotchas.html#thread-safety

pandas는 기본 복사 메커니즘이 없기 때문에 스레드로부터 안전하지 않습니다. Numpy는 원자 복사 작업이 있다고 생각하지만 판다에는이 이상의 레이어가 있습니다.

복사 팬더 작업의 기초가된다 (대부분의 작업은 사용자에게 반환하는 새로운 객체를 생성로)

이 문제를 해결하려면 사소한되지 않습니다 그래서 조금 필요 꽤 무거운 반환 한 비용으로 올 것 이 문제를 제대로 처리 할 수있는 작업이 필요합니다.

가장 쉬운 방법은 스레드간에 개체를 공유하거나 사용량에 따라 잠금을 설정하지 않는 것입니다.

+1

하지만 공유 할 객체가 없으므로 DataFrames는 각 스레드의 로컬 페이지입니다. [This] (https://github.com/numpy/numpy/issues/4642)와 매우 유사하게 보이며 해결책이 있어야합니다. GIL을 공개 할 때 더주의하십시오. [here] (https://github.com/numpy/numpy/pull/4648)를 참조하십시오. 파이썬 API 함수 호출이 필요한 곳에서 GIL을 풀어주지 않겠습니까? – Jaime

+0

nope - 이것들은 모두 numpy/Numexpr (여기에 관련된 c 또는 cython 코드가 필요하지 않습니다.) 그래서 문제가 될 수 있습니다. – Jeff

+0

사실, 이들이 관련된 cython 코드이지만 열 액세스에 있습니다. ''data [ 't']''를 사용하여 다양한 유형의 검사/색인 생성을 할 수 있습니다. 그래도 스레드 안전해야합니다. – Jeff

0

단일 스레드 모드에서 실행되도록 mod_wsgi를 구성하십시오. 프로세스/스레드가 사용하는 어떤 아파치 MPM에 독립적으로 설정 될 수 있도록이 mod_wsgi에 데몬 모드를 사용하고이 경우

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

.

+0

이미이 솔루션을 사용해 보았지만 threads = 1은 일부 요청이 처리 될 때 서버가 멈추게 만듭니다. –

+1

프로세스는이 경우 동시성을 제공하고 왜 둘 이상의 프로세스가 있는지 설명합니다. 실제로 몇 개의 프로세스를 지정 했습니까? 요청에 대한 평균 실행 시간은 얼마이고 처리량은 얼마입니까? 충분한 용량을 적절히 프로비저닝 할 수 있으려면 이들에 대해 알아야합니다. 특정 URL 만 멀티 스레딩에이 문제가있는 경우 여러 mod_wsgi 데몬 프로세스 그룹에 걸쳐 응용 프로그램을 세로로 분할하고 안전하지 않은 URL을 단일 스레드 프로세스에 붙여 넣을 수 있습니다. 다음 게시물을 참조하십시오. http://blog.dscpl.com.au/2014/02/vertically-partitioning-python-web.html –

+0

이것은 흥미 롭습니다. 나는 thread = 1이 잘못된 것이라고 확신했다 ... 나는 프로세스의 수를 찾을 곳을 모른다. 아파치의 기본 설정을 가지고있다. 그러나 pstree는 많이 있다고 (100 개 이상) 있다고합니다. 문제는 파일 업로드에 있습니다 ... 클라이언트가 파일 업로드를 시작하면 (몇 분이 소요될 수 있음) 서버가 무책임하게됩니다. postgresql 트랜잭션과의 상관 관계가 있으며 수동 커밋과 같은 것을 사용하려고 시도했지만 성공하지는 않았다고 생각했습니다. –