여러 프로세스간에 결과 큐 공유


95

multiprocessing모듈에 대한 문서는로 시작하는 프로세스에 큐를 전달하는 방법을 보여줍니다 multiprocessing.Process. 하지만 시작된 비동기 작업자 프로세스와 큐를 공유하려면 어떻게해야 apply_async합니까? 동적 조인이나 다른 것이 필요하지 않습니다. 작업자가 결과를 다시 기지에 (반복적으로)보고하는 방법 일뿐입니다.

import multiprocessing
def worker(name, que):
    que.put("%d is done" % name)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)
    q = multiprocessing.Queue()
    workers = pool.apply_async(worker, (33, q))

이것은 실패합니다 : RuntimeError: Queue objects should only be shared between processes through inheritance. 이것이 의미하는 바를 이해하고 산세 / 산세 제거 (및 모든 특수 Windows 제한 사항)를 요구하는 대신 상속하라는 조언을 이해합니다. 하지만 어떻게 합니까 내가 작업하는 방식으로 큐를 통과? 예를 찾을 수없고 여러 가지 방법으로 실패한 여러 대안을 시도했습니다. 도와주세요?

답변:


137

사용해보십시오 multiprocessing.Manager를 대기열을 관리하고 또한 다른 근로자가 액세스 할 수 있도록 만들 수 있습니다.

import multiprocessing
def worker(name, que):
    que.put("%d is done" % name)

if __name__ == '__main__':
    pool = multiprocessing.Pool(processes=3)
    m = multiprocessing.Manager()
    q = m.Queue()
    workers = pool.apply_async(worker, (33, q))

해냈어, 고마워! 원래 코드의 비동기 호출과 관련이없는 문제가 있었으므로 수정 사항을 답변에 복사했습니다.
alexis

17
queue.Queue()이것에 적합하지 않은 이유 에 대한 설명 이 있습니까?
mrgloom

1
@mrgloom : queue.Queue메모리 내 잠금을 사용하여 스레딩을 위해 빌드되었습니다. 다중 프로세스 환경에서 각 하위 프로세스는 queue.Queue()자체 메모리 공간에서 자체 인스턴스 복사본을 가져옵니다. 하위 프로세스는 메모리를 공유하지 않기 때문입니다 (대부분).
LeoRochael

1
@alexis 여러 작업자가 데이터를 삽입 한 후 Manager (). Queue ()에서 요소를 가져 오는 방법은 무엇입니까?
MSS


14

multiprocessing.Pool이미 공유 된 결과 큐가있는 경우 추가로 Manager.Queue. 별도의 서버 프로세스에 있으며 프록시를 통해 노출되는 후드 아래에 Manager.Queue있는 queue.Queue(다중 스레드 대기열)입니다. 이는 풀의 내부 대기열에 비해 추가 오버 헤드를 추가합니다. 풀의 기본 결과 처리에 의존하는 것과 달리의 결과 Manager.Queue도 순서가 보장되지 않습니다.

작업자 프로세스는로 시작 되지 않습니다 . 이는 .apply_async()인스턴스화 할 때 이미 발생합니다 Pool. 무엇 됩니다 당신이 호출 할 때 시작하는 pool.apply_async()새로운 "작업"입니다. 풀의 작업자 프로세스 multiprocessing.pool.worker는 내부적으로 기능을 실행합니다 . 이 함수는 풀의 내부를 통해 전송 된 새로운 "작업"을 처리 Pool._inqueue하고 Pool._outqueue. 지정한 항목 func은 내에서 실행됩니다 multiprocessing.pool.worker. func에만이 return뭔가 결과가 자동으로 부모에게 전송됩니다.

.apply_async() 즉시 (비동기 적으로) AsyncResult객체 (의 별칭 )를 반환합니다 ApplyResult. .get()실제 결과를 받으려면 해당 개체 에서 호출 (차단)해야합니다. 또 다른 옵션은 결과가 준비되는 즉시 시작되는 콜백 함수 를 등록하는 것 입니다.

from multiprocessing import Pool

def busy_foo(i):
    """Dummy function simulating cpu-bound work."""
    for _ in range(int(10e6)):  # do stuff
        pass
    return i

if __name__ == '__main__':

    with Pool(4) as pool:
        print(pool._outqueue)  # DEMO
        results = [pool.apply_async(busy_foo, (i,)) for i in range(10)]
        # `.apply_async()` immediately returns AsyncResult (ApplyResult) object
        print(results[0])  # DEMO
        results = [res.get() for res in results]
        print(f'result: {results}')       

출력 예 :

<multiprocessing.queues.SimpleQueue object at 0x7fa124fd67f0>
<multiprocessing.pool.ApplyResult object at 0x7fa12586da20>
result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

참고 :에- timeout매개 변수를 지정해도 .get()작업자 내에서 작업의 실제 처리가 중지되는 것은 아니며 multiprocessing.TimeoutError.


흥미롭게도, 제가 얻을 수있는 첫 번째 기회를 시도해 볼게요. 2012 년에는 확실히 이런 식으로 작동하지 않았습니다.
alexis

@alexis Python 2.7 (2010)은 여기에 컨텍스트 관리자와에 대한 error_callback-parameter 만 누락 apply_async되었으므로 그 이후로 많이 변경되지 않았습니다.
Darkonaut 2019

특히 여기에 설명 된대로 일반 목록을 사용하여 비동기 결과를 수집 할 수 있도록 부분 함수와 결합 할 때 콜백 함수가 가장 유용하다는 것을 알았습니다. gist.github.com/Glench/5789879
user5359531
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.