[python] 파이썬에서 비동기 메소드 호출?

파이썬 에서 비동기 메소드 호출을위한 라이브러리가 있는지 궁금합니다 . 다음과 같은 일을 할 수 있다면 좋을 것입니다

@async
def longComputation():
    <code>


token = longComputation()
token.registerCallback(callback_function)
# alternative, polling
while not token.finished():
    doSomethingElse()
    if token.finished():
        result = token.result()

또는 비동기식이 아닌 루틴을 비동기식으로 호출

def longComputation()
    <code>

token = asynccall(longComputation())

언어 핵심에서보다 정교한 전략을 갖는 것이 좋을 것입니다. 이것이 고려 되었습니까?



답변

Python 2.6에 추가 된 다중 처리 모듈을 사용할 수 있습니다 . 프로세스 풀을 사용하고 다음을 사용하여 비동기 적으로 결과를 얻을 수 있습니다.

apply_async(func[, args[, kwds[, callback]]])

예 :

from multiprocessing import Pool

def f(x):
    return x*x

if __name__ == '__main__':
    pool = Pool(processes=1)              # Start a worker processes.
    result = pool.apply_async(f, [10], callback) # Evaluate "f(10)" asynchronously calling callback when finished.

이것은 하나의 대안 일뿐입니다. 이 모듈은 원하는 것을 달성하기 위해 많은 기능을 제공합니다. 또한 이것으로 데코레이터를 만드는 것은 정말 쉽습니다.


답변

다음과 같은 것 :

import threading

thr = threading.Thread(target=foo, args=(), kwargs={})
thr.start() # Will run "foo"
....
thr.is_alive() # Will return whether foo is running currently
....
thr.join() # Will wait till "foo" is done

자세한 내용은 https://docs.python.org/library/threading.html 의 설명서를 참조 하십시오.


답변

Python 3.5부터는 비동기 함수에 향상된 생성기를 사용할 수 있습니다.

import asyncio
import datetime

향상된 생성기 구문 :

@asyncio.coroutine
def display_date(loop):
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        yield from asyncio.sleep(1)


loop = asyncio.get_event_loop()
# Blocking call which returns when the display_date() coroutine is done
loop.run_until_complete(display_date(loop))
loop.close()

새로운 async/await문법 :

async def display_date(loop):
    end_time = loop.time() + 5.0
    while True:
        print(datetime.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        await asyncio.sleep(1)


loop = asyncio.get_event_loop()
# Blocking call which returns when the display_date() coroutine is done
loop.run_until_complete(display_date(loop))
loop.close()


답변

그것은 언어 핵심이 아니지만 원하는 것을 수행하는 매우 성숙한 라이브러리는 Twisted 입니다. 콜백이나 오류 처리기 ( “errbacks”)를 연결할 수있는 Deferred 객체를 소개합니다. 지연은 기본적으로 함수가 결과를 가져 오는 “약속”입니다.


답변

약간 까다 롭지 만 데코레이터를 구현하여 함수를 비동기식으로 만들 수 있습니다. 이 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())

실제 상황에서는 데코레이터에 대해 조금 더 자세히 설명하여 디버깅 (향후 인터페이스를 유지하면서) 또는 예외 처리 기능을 해제 할 수있는 방법을 제공합니다. 그러나 이것이 원리를 충분히 보여줍니다.


답변

다만

import threading, time

def f():
    print "f started"
    time.sleep(3)
    print "f finished"

threading.Thread(target=f).start()


답변

eventlet을 사용할 수 있습니다. 동기 코드 인 것처럼 보이지만 네트워크를 통해 비동기 적으로 작동하도록 할 수 있습니다.

다음은 초소형 크롤러의 예입니다.

urls = ["http://www.google.com/intl/en_ALL/images/logo.gif",
     "https://wiki.secondlife.com/w/images/secondlife.jpg",
     "http://us.i1.yimg.com/us.yimg.com/i/ww/beta/y3.gif"]

import eventlet
from eventlet.green import urllib2

def fetch(url):

  return urllib2.urlopen(url).read()

pool = eventlet.GreenPool()

for body in pool.imap(fetch, urls):
  print "got body", len(body)