멀티 프로세싱 : 클래스에 정의 된 함수에서 Pool.map을 사용하는 방법?


179

내가 다음과 같은 것을 실행할 때 :

from multiprocessing import Pool

p = Pool(5)
def f(x):
     return x*x

p.map(f, [1,2,3])

잘 작동합니다. 그러나 이것을 클래스의 함수로 두는 것 :

class calculate(object):
    def run(self):
        def f(x):
            return x*x

        p = Pool()
        return p.map(f, [1,2,3])

cl = calculate()
print cl.run()

다음과 같은 오류가 발생합니다.

Exception in thread Thread-1:
Traceback (most recent call last):
  File "/sw/lib/python2.6/threading.py", line 532, in __bootstrap_inner
    self.run()
  File "/sw/lib/python2.6/threading.py", line 484, in run
    self.__target(*self.__args, **self.__kwargs)
  File "/sw/lib/python2.6/multiprocessing/pool.py", line 225, in _handle_tasks
    put(task)
PicklingError: Can't pickle <type 'function'>: attribute lookup __builtin__.function failed

Alex Martelli에서 같은 종류의 문제를 다루는 게시물을 보았지만 충분히 명확하지 않았습니다.


1
"이것은 클래스의 함수"입니까? 실제로 실제 오류가 발생하는 코드를 게시 할 수 있습니까? 실제 코드가 없다면 우리는 당신이 뭘 잘못하고 있는지 추측 할 수 있습니다.
S.Lott

일반적으로 파이썬의 표준 피클 모듈보다 강력한 피클 링 모듈이 있습니다 ( 이 답변 에서 언급 한 picloud 모듈과 같습니다 ).
클라우스 세

1
의 클로저와 비슷한 문제가 IPython.Parallel있었지만 객체를 노드로 푸시하면 문제를 해결할 수 있습니다. 멀티 프로세싱 으로이 문제를 해결하는 것은 꽤 성가신 것 같습니다.
Alex S

여기는 calculate피클 가능하므로 1) calculate인스턴스 를 복사하는 생성자로 함수 객체를 만든 다음 2)이 함수 객체의 인스턴스를 Poolmap메소드에 전달하면 해결할 수있는 것처럼 보입니다 . 아니?
rd11

1
@math 저는 파이썬의 "최근 변경 사항"이 도움이 될 것이라고 생각하지 않습니다. multiprocessing모듈 의 일부 제한 사항은 크로스 플랫폼 구현이라는 목표 fork(2)와 Windows에서 비슷한 시스템 호출 이 없기 때문입니다 . Win32 지원에 신경 쓰지 않으면 프로세스 기반의 간단한 해결 방법이있을 수 있습니다. 대신 프로세스의 스레드를 사용할 수 있도록 준비하는 경우 또는, 당신은 대체 할 수 있습니다 from multiprocessing import Poolfrom multiprocessing.pool import ThreadPool as Pool.
Aya

답변:


69

또한 pool.map이 받아 들일 수있는 함수의 종류에 대한 제한에 짜증이났습니다. 나는 이것을 피하기 위해 다음을 썼다. Parmap을 재귀 적으로 사용하더라도 작동하는 것처럼 보입니다.

from multiprocessing import Process, Pipe
from itertools import izip

def spawn(f):
    def fun(pipe, x):
        pipe.send(f(x))
        pipe.close()
    return fun

def parmap(f, X):
    pipe = [Pipe() for x in X]
    proc = [Process(target=spawn(f), args=(c, x)) for x, (p, c) in izip(X, pipe)]
    [p.start() for p in proc]
    [p.join() for p in proc]
    return [p.recv() for (p, c) in pipe]

if __name__ == '__main__':
    print parmap(lambda x: x**x, range(1, 5))

1
이것은 나를 위해 아주 잘 작동했습니다, 감사합니다. 나는 한 가지 약점을 발견했다 : 나는 defaultdict를 통과 한 일부 함수에서 parmap을 사용해 보았고 PicklingError를 다시 얻었습니다. 나는 이것에 대한 해결책을 찾지 못했고, defaultdict를 사용하지 않도록 코드를 재 작업했다.
sans

2
이것은 (기본, 15시 8분 59초 2011 6월 12일) 파이썬 2.7.2에서 [MSC v.1500 32 비트 (인텔)]는 Win32에서 작업을하지 않습니다
ubershmekel

3
이것은 Python 2.7.3 2012 년 8 월 1 일, 05:14:39에서 작동합니다. 거대한 iterables에서는 작동하지 않습니다.-> OSError를 일으 킵니다. [Errno 24] 열린 파이프 수로 인해 열린 파일이 너무 많습니다.
Eiyrioü von Kauyf

이 솔루션은 각 작업 항목에 대한 프로세스를 생성합니다. 아래의 "klaus se"솔루션이 더 효율적입니다.
ypnos

85

"multiprocessing.Pool"을 사용하는 코드는 람다 식에서 작동하지 않고 "multiprocessing.Pool"을 사용하지 않는 코드는 작업 항목만큼 많은 프로세스를 생성하기 때문에 지금까지 게시 된 코드를 사용할 수 없습니다.

미리 정의 된 양의 작업자를 생성하고 유휴 작업자가있는 경우 입력 목록을 반복합니다. 또한 작업자 st ctrl-c 작업에 대해 "데몬"모드를 활성화했습니다.

import multiprocessing


def fun(f, q_in, q_out):
    while True:
        i, x = q_in.get()
        if i is None:
            break
        q_out.put((i, f(x)))


def parmap(f, X, nprocs=multiprocessing.cpu_count()):
    q_in = multiprocessing.Queue(1)
    q_out = multiprocessing.Queue()

    proc = [multiprocessing.Process(target=fun, args=(f, q_in, q_out))
            for _ in range(nprocs)]
    for p in proc:
        p.daemon = True
        p.start()

    sent = [q_in.put((i, x)) for i, x in enumerate(X)]
    [q_in.put((None, None)) for _ in range(nprocs)]
    res = [q_out.get() for _ in range(len(sent))]

    [p.join() for p in proc]

    return [x for i, x in sorted(res)]


if __name__ == '__main__':
    print(parmap(lambda i: i * 2, [1, 2, 3, 4, 6, 7, 8]))

2
parmap기능 을 올바르게 사용하려면 진행률 표시 줄을 어떻게 얻 습니까?
shockburner

2
질문-이 솔루션을 사용했지만 생성 된 파이썬 프로세스가 메모리에서 계속 활성 상태임을 알았습니다. 파맵이 종료 될 때 죽이는 방법에 대한 빠른 생각이 있으십니까?
CompEcon

1
@ klaus-se 의견에 감사의 말을하지 않는 것이 좋지만 귀하의 답변은 나에게 너무 귀중합니다. 나는 당신에게 하나 이상의 명성을 줄 수 있기를 바랍니다 ...
deshtop

2
(None, None)마지막 항목으로 전달 되는 @greole fun은 각 프로세스의 항목 순서 끝에 도달 했음을 나타냅니다 .
aganders3

4
@deshtop : 당신이 충분한 평판을 가지고 있다면 현상금으로 할 수 있습니다 :-)
Mark

57

표준 라이브러리 외부로 이동하지 않으면 다중 처리 및 산세가 중단되고 제한됩니다.

당신의 포크를 사용하는 경우 multiprocessing전화를 pathos.multiprocesssing직접의 멀티 프로세싱에 클래스와 클래스 메소드를 사용할 수있는 map기능. 이 때문입니다 dill대신 사용 pickle하거나 cPickle, 및 dill파이썬에서 거의 모든 것을 직렬화 할 수 있습니다.

pathos.multiprocessing또한 비동기지도 기능을 제공합니다 ... 그리고 수 map(예 : 여러 인수 기능 map(math.pow, [1,2,3], [4,5,6]))

토론 참조 : 멀티 프로세싱과 딜은 무엇을 함께 할 수 있습니까?

및 : http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization

심지어 수정하지 않고 해석기에서 처음 작성한 코드도 처리합니다. 더 취약하고 단일 사례에 특정한 다른 이유는 무엇입니까?

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> class calculate(object):
...  def run(self):
...   def f(x):
...    return x*x
...   p = Pool()
...   return p.map(f, [1,2,3])
... 
>>> cl = calculate()
>>> print cl.run()
[1, 4, 9]

https://github.com/uqfoundation/pathos 에서 코드를 얻으십시오.

그리고 그것이 할 수있는 일을 조금 더 보여주기 위해 :

>>> from pathos.multiprocessing import ProcessingPool as Pool
>>> 
>>> p = Pool(4)
>>> 
>>> def add(x,y):
...   return x+y
... 
>>> x = [0,1,2,3]
>>> y = [4,5,6,7]
>>> 
>>> p.map(add, x, y)
[4, 6, 8, 10]
>>> 
>>> class Test(object):
...   def plus(self, x, y): 
...     return x+y
... 
>>> t = Test()
>>> 
>>> p.map(Test.plus, [t]*4, x, y)
[4, 6, 8, 10]
>>> 
>>> res = p.amap(t.plus, x, y)
>>> res.get()
[4, 6, 8, 10]

1
또한 pathos.multiprocessing amap에는 진행률 표시 줄 및 기타 비동기 프로그래밍을 사용할 수 있는 비동기 맵 ( )이 있습니다.
Mike McKerns

나는 multiprocessing을 즐기면서 평행하지 않은 맵을 거의 대체로 대체 할 수있는 pathos.multiprocessing을 좋아합니다. pathos.multiprocessing.map의 간단한 래퍼를 사용하여 여러 코어에서 읽기 전용 큰 데이터 구조를 처리 할 때 메모리 효율성이 더 뛰어납니다 . 이 저장소를 참조하십시오 .
Fashandge

흥미로운 것 같지만 설치되지 않습니다. 이것은 pip Could not find a version that satisfies the requirement pp==1.5.7-pathos (from pathos)
가주

1
예. 기능을 별도의 패키지로 분할하고 2/3 호환 코드로 변환하면서 한동안 릴리스하지 않았습니다. 위의 많은 부분 multiprocess이 2/3 호환되는 모듈화되었습니다 . stackoverflow.com/questions/27873093/…pypi.python.org/pypi/multiprocess를 참조하십시오 .
Mike McKerns

3
@xApple : 후속 조치와 마찬가지로 pathos새로운 안정적인 릴리스가 있으며 2.x 및 3.x와 호환됩니다.
Mike McKerns

40

내가 아는 한, 현재 문제에 대한 해결책은 없습니다 : 당신이주는 기능은 map()모듈 가져 오기를 통해 액세스 할 수 있어야합니다. 이것이 robert의 코드가 작동하는 이유입니다 f(). 다음 코드를 가져 와서 함수 를 얻을 수 있습니다.

def f(x):
    return x*x

class Calculate(object):
    def run(self):
        p = Pool()
        return p.map(f, [1,2,3])

if __name__ == '__main__':
    cl = Calculate()
    print cl.run()

필자는 실제로 "main"섹션을 추가했는데, 이는 Windows 플랫폼에 대한 권장 사항을 따르기 때문 입니다 ( "예기치 않은 부작용을 일으키지 않고 새로운 Python 인터프리터가 메인 모듈을 안전하게 가져올 수 있는지 확인하십시오").

또한 PEP 8Calculate 을 따르기 위해 대문자 앞에 대문자를 추가했습니다 . :)


18

mrule의 해결책은 정확하지만 버그가 있습니다. 자식이 많은 양의 데이터를 다시 보내면 파이프 버퍼를 채우고 자식을 막을 수 pipe.send()있으며 부모는 자식이 종료되기를 기다리는 중입니다 pipe.join(). 해결책은 아이를 join()먹기 전에 아이의 데이터를 읽는 것입니다. 또한 어린이는 교착 상태를 방지하기 위해 부모의 파이프 끝을 닫아야합니다. 아래 코드는 그 문제를 해결합니다. 또한의 parmap요소 당 하나의 프로세스를 만듭니다 X. 보다 고급 솔루션은 여러 청크 multiprocessing.cpu_count()로 나누고 X결과를 병합하기 전에 사용하는 것입니다. 나는 mrule에 의한 좋은 대답의 간결성을 망치지 않기 위해 독자에게 연습으로 남겨 둡니다. ;)

from multiprocessing import Process, Pipe
from itertools import izip

def spawn(f):
    def fun(ppipe, cpipe,x):
        ppipe.close()
        cpipe.send(f(x))
        cpipe.close()
    return fun

def parmap(f,X):
    pipe=[Pipe() for x in X]
    proc=[Process(target=spawn(f),args=(p,c,x)) for x,(p,c) in izip(X,pipe)]
    [p.start() for p in proc]
    ret = [p.recv() for (p,c) in pipe]
    [p.join() for p in proc]
    return ret

if __name__ == '__main__':
    print parmap(lambda x:x**x,range(1,5))

프로세스 수를 어떻게 선택합니까?
patapouf_ai

그러나 오류 때문에 꽤 빨리 죽습니다 OSError: [Errno 24] Too many open files. 제대로 작동하려면 프로세스 수에 제한이 필요하다고 생각합니다.
patapouf_ai

13

나는 또한 이것으로 고투했다. 간단한 예제로 클래스의 데이터 멤버로서의 기능을 가졌습니다.

from multiprocessing import Pool
import itertools
pool = Pool()
class Example(object):
    def __init__(self, my_add): 
        self.f = my_add  
    def add_lists(self, list1, list2):
        # Needed to do something like this (the following line won't work)
        return pool.map(self.f,list1,list2)  

동일한 클래스 내에서 Pool.map () 호출에서 self.f 함수를 사용해야했고 self.f는 튜플을 인수로 사용하지 않았습니다. 이 함수는 클래스에 포함되었으므로 다른 답변이 제안한 래퍼 유형을 작성하는 방법이 명확하지 않았습니다.

첫 번째 요소가 함수이고 나머지 요소가 eval_func_tuple (f_args)라는 해당 함수의 인수 인 튜플 /리스트를 사용하는 다른 래퍼를 사용하여이 문제를 해결했습니다. 이를 사용하여 문제가있는 줄을 return pool.map (eval_func_tuple, itertools.izip (itertools.repeat (self.f), list1, list2))로 바꿀 수 있습니다. 전체 코드는 다음과 같습니다.

파일 : util.py

def add(a, b): return a+b

def eval_func_tuple(f_args):
    """Takes a tuple of a function and args, evaluates and returns result"""
    return f_args[0](*f_args[1:])  

파일 : main.py

from multiprocessing import Pool
import itertools
import util  

pool = Pool()
class Example(object):
    def __init__(self, my_add): 
        self.f = my_add  
    def add_lists(self, list1, list2):
        # The following line will now work
        return pool.map(util.eval_func_tuple, 
            itertools.izip(itertools.repeat(self.f), list1, list2)) 

if __name__ == '__main__':
    myExample = Example(util.add)
    list1 = [1, 2, 3]
    list2 = [10, 20, 30]
    print myExample.add_lists(list1, list2)  

main.py를 실행하면 [11, 22, 33]이 나타납니다. 예를 들어 eval_func_tuple을 수정하여 키워드 인수를 사용할 수도 있습니다.

또 다른 참고로, 다른 답변에서, "parmap"기능은 사용 가능한 CPU 수보다 많은 프로세스의 경우 더 효율적으로 만들 수 있습니다. 아래에서 수정 된 버전을 복사하고 있습니다. 이것은 첫 번째 게시물이며 원래 답변을 직접 수정해야하는지 잘 모르겠습니다. 또한 일부 변수의 이름을 바꿨습니다.

from multiprocessing import Process, Pipe  
from itertools import izip  

def spawn(f):  
    def fun(pipe,x):  
        pipe.send(f(x))  
        pipe.close()  
    return fun  

def parmap(f,X):  
    pipe=[Pipe() for x in X]  
    processes=[Process(target=spawn(f),args=(c,x)) for x,(p,c) in izip(X,pipe)]  
    numProcesses = len(processes)  
    processNum = 0  
    outputList = []  
    while processNum < numProcesses:  
        endProcessNum = min(processNum+multiprocessing.cpu_count(), numProcesses)  
        for proc in processes[processNum:endProcessNum]:  
            proc.start()  
        for proc in processes[processNum:endProcessNum]:  
            proc.join()  
        for proc,c in pipe[processNum:endProcessNum]:  
            outputList.append(proc.recv())  
        processNum = endProcessNum  
    return outputList    

if __name__ == '__main__':  
    print parmap(lambda x:x**x,range(1,5))         

8

나는 klaus se와 aganders3의 대답을 가져 와서 더 읽기 쉽고 하나의 파일로 보유하는 문서화 된 모듈을 만들었습니다. 프로젝트에 추가하면됩니다. 옵션 진행 바가 있습니다!

"""
The ``processes`` module provides some convenience functions
for using parallel processes in python.

Adapted from http://stackoverflow.com/a/16071616/287297

Example usage:

    print prll_map(lambda i: i * 2, [1, 2, 3, 4, 6, 7, 8], 32, verbose=True)

Comments:

"It spawns a predefined amount of workers and only iterates through the input list
 if there exists an idle worker. I also enabled the "daemon" mode for the workers so
 that KeyboardInterupt works as expected."

Pitfalls: all the stdouts are sent back to the parent stdout, intertwined.

Alternatively, use this fork of multiprocessing: 
https://github.com/uqfoundation/multiprocess
"""

# Modules #
import multiprocessing
from tqdm import tqdm

################################################################################
def apply_function(func_to_apply, queue_in, queue_out):
    while not queue_in.empty():
        num, obj = queue_in.get()
        queue_out.put((num, func_to_apply(obj)))

################################################################################
def prll_map(func_to_apply, items, cpus=None, verbose=False):
    # Number of processes to use #
    if cpus is None: cpus = min(multiprocessing.cpu_count(), 32)
    # Create queues #
    q_in  = multiprocessing.Queue()
    q_out = multiprocessing.Queue()
    # Process list #
    new_proc  = lambda t,a: multiprocessing.Process(target=t, args=a)
    processes = [new_proc(apply_function, (func_to_apply, q_in, q_out)) for x in range(cpus)]
    # Put all the items (objects) in the queue #
    sent = [q_in.put((i, x)) for i, x in enumerate(items)]
    # Start them all #
    for proc in processes:
        proc.daemon = True
        proc.start()
    # Display progress bar or not #
    if verbose:
        results = [q_out.get() for x in tqdm(range(len(sent)))]
    else:
        results = [q_out.get() for x in range(len(sent))]
    # Wait for them to finish #
    for proc in processes: proc.join()
    # Return results #
    return [x for i, x in sorted(results)]

################################################################################
def test():
    def slow_square(x):
        import time
        time.sleep(2)
        return x**2
    objs    = range(20)
    squares = prll_map(slow_square, objs, 4, verbose=True)
    print "Result: %s" % squares

편집 : @ alexander-mcfarlane 제안 및 테스트 기능 추가


진행률 표시 줄의 한 가지 문제 ...이 표시 줄은 워크로드가 프로세서에서 얼마나 비효율적으로 분할되었는지 측정합니다. 작업 부하가 완벽하게 분할되면 모든 프로세서가 join()동시에 작동 100%하며 tqdm디스플레이 에서 플래시가 완료 됩니다. 각 프로세서는 바이어스 부하가있는 경우 유용하게 사용될 수있는 유일한 시간이다
알렉산더 맥팔레인

1
이동 tqdm()라인을 포장 : result = [q_out.get() for _ in tqdm(sent)]그것은 훨씬 더 잘 작동 - 많은 노력을 정말 너무 한 감사 불구하고
알렉산더 맥팔레인

그 조언에 감사드립니다, 나는 그것을 시도하고 대답을 업데이트 할 것입니다!
xApple

답변이 업데이트되고 진행률 표시 줄이 훨씬 잘 작동합니다!
xApple

8

나는 이것이 6 년 전에 지금 요청되었다는 것을 알고 있지만 위의 제안 중 일부는 끔찍하게 복잡해 보이지만 내 솔루션은 실제로 매우 간단했습니다.

내가해야 할 일은 pool.map () 호출을 도우미 함수로 래핑하는 것입니다. 메서드에 대한 인수와 함께 클래스 객체를 튜플로 전달하면 다음과 같이 보입니다.

def run_in_parallel(args):
    return args[0].method(args[1])

myclass = MyClass()
method_args = [1,2,3,4,5,6]
args_map = [ (myclass, arg) for arg in method_args ]
pool = Pool()
pool.map(run_in_parallel, args_map)

7

클래스에서 정의 된 함수 (클래스 내의 함수 내에서도)는 실제로 피클되지 않습니다. 그러나 이것은 작동합니다.

def f(x):
    return x*x

class calculate(object):
    def run(self):
        p = Pool()
    return p.map(f, [1,2,3])

cl = calculate()
print cl.run()

15
고맙지 만 클래스 외부에서 함수를 정의하는 것은 약간 더럽습니다. 클래스는 주어진 작업을 수행하는 데 필요한 모든 것을 번들로 제공해야합니다.
Mermoz

3
@ 메모 즈 : "클래스가 필요한 모든 것을 묶어야한다" 나는 이것에 대한 많은 예를 찾을 수 없습니다. 대부분의 클래스는 다른 클래스 또는 함수에 의존합니다. 왜 클래스 의존성을 "더티 (dirty)"라고 부르는가? 의존성에 어떤 문제가 있습니까?
S.Lott

글쎄, 함수는 기존 클래스 데이터를 수정해서는 안됩니다. 다른 프로세스에서 버전을 수정하기 때문에 정적 메서드 일 수 있습니다. 정적 메소드를 피클 링 할 수 있습니다 : stackoverflow.com/questions/1914261/… 또는이 사소한 일에는 람다를 사용할 수 있습니다.
robert

6

이 질문은 8 년 10 개월 전에 요청되었지만 내 해결책을 제시하고자합니다.

from multiprocessing import Pool

class Test:

    def __init__(self):
        self.main()

    @staticmethod
    def methodForMultiprocessing(x):
        print(x*x)

    def main(self):
        if __name__ == "__main__":
            p = Pool()
            p.map(Test.methodForMultiprocessing, list(range(1, 11)))
            p.close()

TestObject = Test()

클래스 함수를 정적 메소드로 만들어야합니다. 그러나 클래스 방법으로도 가능합니다.

from multiprocessing import Pool

class Test:

    def __init__(self):
        self.main()

    @classmethod
    def methodForMultiprocessing(cls, x):
        print(x*x)

    def main(self):
        if __name__ == "__main__":
            p = Pool()
            p.map(Test.methodForMultiprocessing, list(range(1, 11)))
            p.close()

TestObject = Test()

파이썬 3.7.3에서 테스트


3

klaus se의 방법은 작은 목록으로 저를 위해 일하는 동안 항목 수가 ~ 1000 이상일 때 중단되기 때문에 수정했습니다. None중지 조건 으로 한 번에 하나씩 작업을 푸시하는 대신 입력 큐를 한 번에 모두로드하고 프로세스가 비워 질 때까지 프로세스를 중단시킵니다.

from multiprocessing import cpu_count, Queue, Process

def apply_func(f, q_in, q_out):
    while not q_in.empty():
        i, x = q_in.get()
        q_out.put((i, f(x)))

# map a function using a pool of processes
def parmap(f, X, nprocs = cpu_count()):
    q_in, q_out   = Queue(), Queue()
    proc = [Process(target=apply_func, args=(f, q_in, q_out)) for _ in range(nprocs)]
    sent = [q_in.put((i, x)) for i, x in enumerate(X)]
    [p.start() for p in proc]
    res = [q_out.get() for _ in sent]
    [p.join() for p in proc]

    return [x for i,x in sorted(res)]

편집 : 불행히도 이제 시스템 에서이 오류가 발생합니다. 멀티 프로세싱 큐 최대 크기 제한은 32767 이므로 해결 방법이 도움이되기를 바랍니다.


1

오류가 말한 것처럼 Pool클래스의 객체 목록 에서 객체를 수동으로 무시하는 경우 아무런 문제없이 코드를 실행할 수 있습니다 pickle. 다음과 같이 __getstate__기능을 사용 하여이 작업을 수행 할 수 있습니다 ( 여기 에서도보십시오). Pool개체는 찾을 시도합니다 __getstate____setstate__기능을하고 실행할 때 그것을 발견하면 그들을 실행 map, map_async등 :

class calculate(object):
    def __init__(self):
        self.p = Pool()
    def __getstate__(self):
        self_dict = self.__dict__.copy()
        del self_dict['p']
        return self_dict
    def __setstate__(self, state):
        self.__dict__.update(state)

    def f(self, x):
        return x*x
    def run(self):
        return self.p.map(self.f, [1,2,3])

그런 다음 수행하십시오.

cl = calculate()
cl.run()

당신에게 출력을 줄 것입니다 :

[1, 4, 9]

Python 3.x에서 위의 코드를 테스트했으며 작동합니다.


0

이 방법을 사용했는지 확실하지 않지만 사용중인 해결 방법은 다음과 같습니다.

from multiprocessing import Pool

t = None

def run(n):
    return t.f(n)

class Test(object):
    def __init__(self, number):
        self.number = number

    def f(self, x):
        print x * self.number

    def pool(self):
        pool = Pool(2)
        pool.map(run, range(10))

if __name__ == '__main__':
    t = Test(9)
    t.pool()
    pool = Pool(2)
    pool.map(run, range(10))

출력은 다음과 같아야합니다.

0
9
18
27
36
45
54
63
72
81
0
9
18
27
36
45
54
63
72
81

0
class Calculate(object):
  # Your instance method to be executed
  def f(self, x, y):
    return x*y

if __name__ == '__main__':
  inp_list = [1,2,3]
  y = 2
  cal_obj = Calculate()
  pool = Pool(2)
  results = pool.map(lambda x: cal_obj.f(x, y), inp_list)

클래스의 각 인스턴스마다이 함수를 적용 할 가능성이 있습니다. 그런 다음 여기에도 해결책이 있습니다.

class Calculate(object):
  # Your instance method to be executed
  def __init__(self, x):
    self.x = x

  def f(self, y):
    return self.x*y

if __name__ == '__main__':
  inp_list = [Calculate(i) for i in range(3)]
  y = 2
  pool = Pool(2)
  results = pool.map(lambda x: x.f(y), inp_list)

0

여기 내 솔루션이 있습니다. 여기서 다른 대부분의 것보다 약간 덜 해킹 적이라고 생각합니다. nightowl의 답변과 비슷합니다.

someclasses = [MyClass(), MyClass(), MyClass()]

def method_caller(some_object, some_method='the method'):
    return getattr(some_object, some_method)()

othermethod = partial(method_caller, some_method='othermethod')

with Pool(6) as pool:
    result = pool.map(othermethod, someclasses)

0

에서 http://www.rueckstiess.net/research/snippets/show/ca1d7d90http://qingkaikong.blogspot.com/2016/12/python-parallel-method-in-class.html

외부 함수를 만들고 클래스 자체 객체로 시드 할 수 있습니다.

from joblib import Parallel, delayed
def unwrap_self(arg, **kwarg):
    return square_class.square_int(*arg, **kwarg)

class square_class:
    def square_int(self, i):
        return i * i

    def run(self, num):
        results = []
        results = Parallel(n_jobs= -1, backend="threading")\
            (delayed(unwrap_self)(i) for i in zip([self]*len(num), num))
        print(results)

또는 joblib이없는 경우 :

from multiprocessing import Pool
import time

def unwrap_self_f(arg, **kwarg):
    return C.f(*arg, **kwarg)

class C:
    def f(self, name):
        print 'hello %s,'%name
        time.sleep(5)
        print 'nice to meet you.'

    def run(self):
        pool = Pool(processes=2)
        names = ('frank', 'justin', 'osi', 'thomas')
        pool.map(unwrap_self_f, zip([self]*len(names), names))

if __name__ == '__main__':
    c = C()
    c.run()

0

이것은 매우 좋은 해결책은 아니지만 제 경우에는 다음과 같이 해결합니다.

from multiprocessing import Pool

def foo1(data):
    self = data.get('slf')
    lst = data.get('lst')
    return sum(lst) + self.foo2()

class Foo(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def foo2(self):
        return self.a**self.b   

    def foo(self):
        p = Pool(5)
        lst = [1, 2, 3]
        result = p.map(foo1, (dict(slf=self, lst=lst),))
        return result

if __name__ == '__main__':
    print(Foo(2, 4).foo())

self해당 함수를 통해 클래스의 속성과 함수에 액세스해야하므로 함수 에 전달 해야했습니다. 이것은 나를 위해 일하고 있습니다. 정정 및 제안은 언제나 환영합니다.


0

다음은 python3에서 다중 처리 풀을 사용하기 위해 작성한 보일러 플레이트입니다. 특히 python3.7.7이 테스트를 실행하는 데 사용되었습니다. 를 사용하여 가장 빠른 달리기를 얻었습니다 imap_unordered. 시나리오를 연결하고 사용해보십시오. 사용 timeit하거나 time.time()가장 적합한 것을 알아낼 수 있습니다.

import multiprocessing
import time

NUMBER_OF_PROCESSES = multiprocessing.cpu_count()
MP_FUNCTION = 'starmap'  # 'imap_unordered' or 'starmap' or 'apply_async'

def process_chunk(a_chunk):
    print(f"processig mp chunk {a_chunk}")
    return a_chunk


map_jobs = [1, 2, 3, 4]

result_sum = 0

s = time.time()
if MP_FUNCTION == 'imap_unordered':
    pool = multiprocessing.Pool(processes=NUMBER_OF_PROCESSES)
    for i in pool.imap_unordered(process_chunk, map_jobs):
        result_sum += i
elif MP_FUNCTION == 'starmap':
    pool = multiprocessing.Pool(processes=NUMBER_OF_PROCESSES)
    try:
        map_jobs = [(i, ) for i in map_jobs]
        result_sum = pool.starmap(process_chunk, map_jobs)
        result_sum = sum(result_sum)
    finally:
        pool.close()
        pool.join()
elif MP_FUNCTION == 'apply_async':
    with multiprocessing.Pool(processes=NUMBER_OF_PROCESSES) as pool:
        result_sum = [pool.apply_async(process_chunk, [i, ]).get() for i in map_jobs]
    result_sum = sum(result_sum)
print(f"result_sum is {result_sum}, took {time.time() - s}s")

위의 시나리오에서 imap_unordered실제로 나에게 최악의 성능을 보이는 것 같습니다. 사례를 시험해보고 실행하려는 머신에서 벤치마킹하십시오. 프로세스 풀 에 대해서도 읽어보십시오 . 건배!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.