2012-09-18 1 views
7

여러 발신자와 수신자가있는 경우 Pipes이 안전하지 않은 이유를 알지 못합니다.파이썬 다중 처리 파이프가 안전하지 않은 이유는 무엇입니까?

Queues을 사용하여 다음 코드를 코드로 변환하는 방법은 무엇입니까? Queues 닫히면 EOFError을 던지지 않으므로 프로세스가 멈추지 않습니다. 끝내기 위해 'Poison'메시지를 보내야합니다 (이 방법으로 모든 프로세스에 적어도 하나의 독이 있음을 확신합니다).

그렇지 않으면 (내가 여기에 10 개의 메시지를 보냈을 때까지) 나는 파이프 p1을 열어두고 싶습니다.


from multiprocessing import Pipe, Process 
from random import randint, random 
from time import sleep 

def job(name, p_in, p_out): 
    print(name + ' starting') 
    nb_msg = 0 
    try: 
     while True: 
      x = p_in.recv() 
      print(name + ' receives ' + x) 
      nb_msg = nb_msg + 1 
      p_out.send(x) 
      sleep(random()) 
    except EOFError: 
     pass 
    print(name + ' ending ... ' + str(nb_msg) + ' message(s)') 

if __name__ == '__main__': 
    p1_in, p1_out = Pipe() 
    p2_in, p2_out = Pipe() 

    proc = [] 

    for i in range(3): 
     p = Process(target=job, args=(str(i), p1_out, p2_in)) 
     p.start() 
     proc.append(p) 

    for x in range(10): 
     p1_in.send(chr(97+x)) 
    p1_in.close() 
    for p in proc: 
     p.join() 
    p1_out.close() 
    p2_in.close() 

    try: 
     while True: 
      print(p2_out.recv()) 
    except EOFError: 
     pass 

    p2_out.close() 

답변

13

본질적 문제는 Pipe 플랫폼이 정의 파이프 객체의 thin 래퍼이다. recv은 완전한 파이썬 객체가 얻어 질 때까지 반복적으로 바이트 버퍼를 받는다. 두 스레드 또는 프로세스가 동일한 파이프에서 recv을 사용하면 읽기가 인터리브되어 각 프로세스에 피클 링 된 개체의 절반이 남게되어 데이터가 손상 될 수 있습니다. Queue은 프로세스 간 적절한 동기화를 수행하지만 더 복잡합니다.

multiprocessing 문서가 말했듯이 : 두 개의 프로세스 (또는 스레드)를 읽거나 동시에 파이프의 같은 말에 쓰기를 시도하는 경우 파이프의 데이터가 손상 될 수 있음을

주 . 물론 파이프의 다른 끝을 사용하는 프로세스로 인해 손상 될 위험이 없습니다.

독약을 끊임없이 보낼 필요는 없습니다. 1 인당 1 대만 있으면됩니다. 각 작업자는 나가기 전에 정확히 하나의 독약을 집 어서 작업자가 어떻게 든 메시지를 놓칠 위험이 없습니다.

"작업자 프로세스"모델을 다시 구현하는 대신 multiprocessing.Pool을 사용하는 것도 고려해야합니다. Pool에는 여러 스레드에서 작업을 분산시키는 데 매우 유용한 방법이 많이 있습니다.

+0

파이프의'recv'와'send'를 사용할 때'multiprocessing.Lock()'을 사용하면 어떨까요? 안전한가 (그리고 효율적인가)? – thuzhf

+0

이렇게하면 기본적으로'Queue' -'다중 처리 '로 끝날 것입니다 .Queue는 잠금 쌍이 첨부 된 (각 방향에 하나씩)'Pipe'입니다. 따라서 안전하고 합리적으로 효율적이지만, 바퀴 달린 자전거를 직접 개조해야합니다. 왜 '대기열'을 사용하지 않을까요? – nneonneo

7

여러 개의 보낸 사람과받는 사람이있을 때 왜 파이프가 안전하지 않은지 알 수 없습니다.

소스 A와 B의 파이프에 물을 동시에 넣는 것을 고려하십시오. 파이프의 다른 끝 부분에서 물의 어느 부분이 A 또는 B에서 왔는지를 알 수는 없습니다. :)

파이프는 바이트 수준에서 데이터 스트림을 전송합니다. 그 위에 통신 프로토콜이 없으면 메시지가 무엇인지 모르기 때문에 메시지 무결성을 보장 할 수 없습니다. 따라서 여러 발신자가있는 파이프를 사용하는 것이 '안전하지 않은'것은 아닙니다. 이것은 주요한 설계상의 결함이며 통신 문제로 이어질 가능성이 큽니다.

그러나 큐는 상위 수준에서 구현됩니다. 그것들은 메시지 (또는 추상적 인 객체들)을 의사 소통하기 위해 고안되었습니다. 대기열은 메시지/객체를 자체 포함 된 상태로 유지하기 위해 만들어집니다. 다중 소스는 객체를 대기열에 넣을 수 있고 여러 소비자는 이러한 객체를 가져올 수 있지만 100 % 단위로 대기열에 들어간 것은 단위로도 나오게됩니다.아주 잠시 후

편집 : 전송로 내가 바이트 스트림에 그를 추가해야

는, 모든 바이트가 같은 순서로 검색됩니다 (보장). 여러 발신자의 문제는 전송 순서 (입력 순서)가 이미 명확하지 않거나 임의적 일 수 있습니다. 즉, 여러 스트림이 예측할 수없는 방식으로 혼합 될 수 있습니다.

공용 큐 구현을 사용하면 여러 명의 보낸 사람이 있어도 단일 메시지가 그대로 유지됩니다. 메시지는 보낸 순서대로 검색됩니다. 그러나 여러 경쟁 송신자가 있고 더 이상의 동기화 메커니즘이없는 경우에도 입력 메시지의 순서에 대한 보장이 없습니다.