2014-12-13 4 views
3

내가하려고하는 것이 올바른 방법이지만 확실하지 않은 경우 여기에 있습니다. 내 프로그램이 고도로 병렬화되어 있어야하므로 2-3 개의 프로세스와 각 프로세스를 만들 수 있다고 생각했습니다. 2-3 스레드를 가질 수 있습니다.멀티 스레드와 결합 된 파이썬 멀티 프로세싱

1) 가능합니까? 2) 거기에 어떤 점이 있습니까? 3) 이것은 내 코드이지만 프로세스에 참여하려고하면 중단됩니다.

PQ = multiprocessing.Queue() 

[...]

def node(self, files, PQ): 

     l1, l2 = self.splitList(files) 
     p1 = multiprocessing.Process(target=self.filePro, args=(l1,PQ,)) 
     p2 = multiprocessing.Process(target=self.filePro, args=(l2,PQ,)) 
     p1.daemon = True 
     p2.daemon = True 
     p1.start() 
     p2.start() 

     p1.join() # HANGS HERE 
     p2.join() 
     while 1: 
      if PQ.empty(): 
       break 
      else: 
       print(PQ.get()) 
     PQ.join() 

    def filePro(self,lst,PQ): 
     TQ = queue.Queue() 
     l1, l2 = self.splitList(lst) 
     t1 = threading.Thread(target=self.fileThr, args=('a',l1,TQ,)) 
     t2 = threading.Thread(target=self.fileThr, args=('b',l2,TQ,)) 
     t1.daemon = True 
     t2.daemon = True 
     t1.start() 
     t2.start() 

     t1.join() 
     t2.join() 
     while 1: 
      if TQ.empty(): 
       break 
      else: 
       PQ.put(TQ.get()) 
       TQ.task_done() 
     TQ.join() 

def fileThr(self,id,lst,TQ): 
     while lst: 
      tmp_path = lst.pop() 
      if (not tmp_path[1]): 
       continue 
      for item in tmp_path[1]: 
       TQ.put(1) 
     TQ.join() 
+0

CPU 사용을 극대화해야 할 때 프로세스를 사용하고 디스크 액세스, 네트워크 등의 작업을 차단할 때 스레드를 사용합니다. 많은 파일을 다운로드하는 스크립트가 있으면 스레드 풀을 만들어 사용합니다 . CPU가 최고가되는 분산 계산이 있다면 프로세스 풀을 사용할 것입니다. –

+0

코드를 디버그하기를 원하면 [최소, 완전하고 검증 가능한 예제] (http://stackoverflow.com/help/mcve)가 필요합니다. – abarnert

답변

6

1)이 가능한가?

예.


2)에 어느 시점이 있습니까?

예. 하지만 일반적으로 당신이 찾고있는 요점은 아닙니다.

첫째, 거의 모든 최신 운영 체제는 "평면"스케줄러를 사용합니다. 3 개 프로그램이나 8 개 프로그램에서 8 스레드에 걸쳐 흩어져 8 개 스레드 사이에는 차이가 없습니다. *

* 일부 프로그램 주의 깊게 당신이 알고있는 어떤 장소에 intraprocess 전용 잠금이나 다른 동기화 프리미티브를 사용하여 큰 이점을 얻을 수 있습니다 동일한 프로그램의 스레드와 만 공유 할 수 있습니다. 물론 그 위치에서 공유 메모리를 사용하지 않아도됩니다.하지만 프로세스간에 스레드와 스레드간에 작업을 균등하게 분산시키지 않으면 이점을 얻을 수 없습니다.

둘째, 예전의 SunOS를 사용하더라도, 기본 CPython 인터프리터에서 GIL (Global Interpreter Lock)은 한 번에 하나의 스레드 만 파이썬 코드를 실행할 수 있도록합니다. 명시 적으로 GIL을 해제하는 C 확장 라이브러리에서 코드를 실행하는 경우 (일부 NumPy 함수와 마찬가지로) 스레드가 도움이 될 수 있지만 그렇지 않으면 모두 결국 직렬화됩니다.

스레드와 프로세스가 함께 사용되는 주된 경우는 CPU 바인딩 및 I/O 바인딩 작업을 모두 수행하는 경우입니다. 이 경우 대개 다른 사람에게 먹이를주고 있습니다. I/O가 CPU에 공급하는 경우 주 프로세스의 단일 스레드 풀을 사용하여 I/O를 처리 한 다음 작업자 프로세스 풀을 사용하여 결과에서 CPU 작업을 수행합니다. 그 반대의 경우 작업자 프로세스 풀을 사용하여 CPU 작업을 수행 한 다음 각 작업자 프로세스가 스레드 풀을 사용하여 I/O를 수행하게하십시오.


3)이 내 코드는하지만 난 프로세스에 가입하려고 할 때이 중단됩니다.

minimal, complete, verifiable example을 제공하지 않으면 코드를 디버깅하기가 매우 어렵습니다.

그러나 명백한 문제가 하나 있습니다.

당신은 t1t2 생산자로서 소비자와 filePro 부모, 생산자 - 소비자 큐으로 TQ를 사용하려고하고 있습니다. t1.join()t2.join() 반환 전까지는 고객이 TQ.task_done()으로 전화하지 않습니다. 이러한 스레드는 완료 될 때까지 발생하지 않습니다. 그러나 그 생산자들은 당신이 TQ.task_done()에 전화하기를 기다리고 있기 때문에 끝나지 않을 것입니다. 그래서 교착 상태에 빠졌습니다.

그리고 각 자식 프로세스의 주 스레드가 교착 상태에 있기 때문에 절대로 완료되지 않으므로 p1.join()은 영원히 차단됩니다.

작업을 수행하기 전에 다른 스레드가 완료 될 때까지 주 스레드를 기다리고 싶다면 제작자 - 소비자 관용구가 필요하지 않습니다. 아이들이 TQ.join() 번으로 전화하지 않고 퇴근하고 퇴근하도록하고, 부모의 TQ.task_done()으로 귀찮게하지 마십시오. (PQ을 사용하면 이미 올바르게 수행하고 있습니다.)

루프가 끝나기 전까지는 병렬 처리를 수행하고 싶다면 join 하위 스레드를 시도하지 마십시오.

+0

감사합니다. 그것은 아주 완벽한 답변이었습니다. 그러나 이제 2 번째 대답에 관해 1 개의 질문이 생깁니다. 1) GIL에 관해서는, 내가 30 개의 스레드를 생성한다면 1을 산란하는 것과 같을까요? 당신은 그들이 어쨌든 직렬화되게된다고 말했기 때문에 ... –

+0

@AngeloUknown : 아니, 그것은 거의 동일하지 않습니다. 당신은 * 병렬 처리 *를 얻지 못합니다. 즉, 32 개의 코어가 있더라도 30 개의 스레드를 사용하는 것은 1을 사용하는 것보다 빠르게 실행되지 않습니다. 그러나 * 동시성 *을 얻습니다. 스레드는 자동으로 작업 사이에 작업을 인터리빙합니다. 예를 들어 하나의 스레드가 I/O를 기다리고 있으면 시스템은 전체 프로그램을 차단하는 대신 다른 스레드를 실행하도록 예약합니다. _explicitly_ deadlocks (예제에서와 같이) 코드를 작성하지 않으면 한 스레드가 다른 스레드를 처리하지 못하게합니다. – abarnert

+0

@AngeloUknown : 파이썬 관련 용어의 차이점을 설명하는 좋은 소스를 찾을 수 없지만 하스켈 위키의 [병렬 처리 대 동시성] (https://www.haskell.org/haskellwiki/Parallelism_vs._Concurrency) 하스켈 관련 항목을 무시하면 꽤 좋은 개요입니다. – abarnert

관련 문제