약간 까다 롭지 만 데코레이터를 구현하여 함수를 비동기식으로 만들 수 있습니다. 이 multiprocessing
모듈은 작은 단점과 임의의 제한 사항으로 가득 차 있습니다. 친숙한 인터페이스 뒤에 모듈을 캡슐화해야하는 더 많은 이유가 있습니다.
from inspect import getmodule
from multiprocessing import Pool
def async(decorated):
r'''Wraps a top-level function around an asynchronous dispatcher.
when the decorated function is called, a task is submitted to a
process pool, and a future object is returned, providing access to an
eventual return value.
The future object has a blocking get() method to access the task
result: it will return immediately if the job is already done, or block
until it completes.
This decorator won't work on methods, due to limitations in Python's
pickling machinery (in principle methods could be made pickleable, but
good luck on that).
'''
# Keeps the original function visible from the module global namespace,
# under a name consistent to its __name__ attribute. This is necessary for
# the multiprocessing pickling machinery to work properly.
module = getmodule(decorated)
decorated.__name__ += '_original'
setattr(module, decorated.__name__, decorated)
def send(*args, **opts):
return async.pool.apply_async(decorated, args, opts)
return send
아래 코드는 데코레이터 사용법을 보여줍니다.
@async
def printsum(uid, values):
summed = 0
for value in values:
summed += value
print("Worker %i: sum value is %i" % (uid, summed))
return (uid, summed)
if __name__ == '__main__':
from random import sample
# The process pool must be created inside __main__.
async.pool = Pool(4)
p = range(0, 1000)
results = []
for i in range(4):
result = printsum(i, sample(p, 100))
results.append(result)
for result in results:
print("Worker %i: sum value is %i" % result.get())
실제 상황에서는 데코레이터에 대해 조금 더 자세히 설명하여 디버깅 (향후 인터페이스를 유지하면서) 또는 예외 처리 기능을 해제 할 수있는 방법을 제공합니다. 그러나 이것이 원리를 충분히 보여줍니다.
async
와await
3.5의 새롭고 구문이 있습니다).