복붙노트

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

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())

언어 핵심에서보다 세련된 전략을 원한다면 좋을 것입니다. 이것이 고려 되었습니까?

해결법

  1. ==============================

    1.파이썬 2.6에서 추가 된 멀티 프로세싱 모듈을 사용할 수 있습니다. 프로세스 풀을 사용하고 다음과 같이 비동기 적으로 결과를 얻을 수 있습니다.

    파이썬 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.
    

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

  2. ==============================

    2.같은 것 :

    같은 것 :

    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/2/library/threading.html#module-threading의 설명서를 참조하십시오. 이 코드는 Python 3에서도 작동해야합니다.

  3. ==============================

    3.파이썬 3.5부터 비동기 함수를 위해 향상된 생성기를 사용할 수 있습니다.

    파이썬 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 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()
    
  4. ==============================

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

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

  5. ==============================

    5.다소 비효율적이지만 비동기 함수를 만들기 위해 데코레이터를 구현할 수 있습니다. 멀티 프로세싱 모듈은 약간의 단점과 겉으로보기에 임의의 제한 사항으로 가득 차 있습니다.하지만 친숙한 인터페이스 뒤에 캡슐화해야 할 이유가 더 많습니다.

    다소 비효율적이지만 비동기 함수를 만들기 위해 데코레이터를 구현할 수 있습니다. 멀티 프로세싱 모듈은 약간의 단점과 겉으로보기에 임의의 제한 사항으로 가득 차 있습니다.하지만 친숙한 인터페이스 뒤에 캡슐화해야 할 이유가 더 많습니다.

    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())
    

    실세계의 경우, 장식 자에 대해 좀 더 자세하게 설명하고, 디버깅을 위해 (미래의 인터페이스를 유지하면서) 또는 예외 처리를위한 기능을 해제하는 방법을 제공합니다. 그러나 나는 이것이 원리를 충분히 잘 보여주고 있다고 생각한다.

  6. ==============================

    6.다만

    다만

    import threading, time
    
    def f():
        print "f started"
        time.sleep(3)
        print "f finished"
    
    threading.Thread(target=f).start()
    
  7. ==============================

    7.내 솔루션은 다음과 같습니다.

    내 솔루션은 다음과 같습니다.

    import threading
    
    class TimeoutError(RuntimeError):
        pass
    
    class AsyncCall(object):
        def __init__(self, fnc, callback = None):
            self.Callable = fnc
            self.Callback = callback
    
        def __call__(self, *args, **kwargs):
            self.Thread = threading.Thread(target = self.run, name = self.Callable.__name__, args = args, kwargs = kwargs)
            self.Thread.start()
            return self
    
        def wait(self, timeout = None):
            self.Thread.join(timeout)
            if self.Thread.isAlive():
                raise TimeoutError()
            else:
                return self.Result
    
        def run(self, *args, **kwargs):
            self.Result = self.Callable(*args, **kwargs)
            if self.Callback:
                self.Callback(self.Result)
    
    class AsyncMethod(object):
        def __init__(self, fnc, callback=None):
            self.Callable = fnc
            self.Callback = callback
    
        def __call__(self, *args, **kwargs):
            return AsyncCall(self.Callable, self.Callback)(*args, **kwargs)
    
    def Async(fnc = None, callback = None):
        if fnc == None:
            def AddAsyncCallback(fnc):
                return AsyncMethod(fnc, callback)
            return AddAsyncCallback
        else:
            return AsyncMethod(fnc, callback)
    

    요청한대로 정확히 작동합니다.

    @Async
    def fnc():
        pass
    
  8. ==============================

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

    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)
    
  9. ==============================

    9.이 기능이 나를 위해 작동하면 함수를 호출하고 새로운 스레드에 자체를 디스패치합니다.

    이 기능이 나를 위해 작동하면 함수를 호출하고 새로운 스레드에 자체를 디스패치합니다.

    from thread import start_new_thread
    
    def dowork(asynchronous=True):
        if asynchronous:
            args = (False)
            start_new_thread(dowork,args) #Call itself on a new thread.
        else:
            while True:
                #do something...
                time.sleep(60) #sleep for a minute
        return
    
  10. ==============================

    10.스레드를 사용하지 않는 이유가 있습니까? 스레딩 클래스를 사용할 수 있습니다. finished () 함수 대신 isAlive ()를 사용하십시오. result () 함수는 스레드를 join ()하여 결과를 검색 할 수 있습니다. 그리고 가능한 경우 run () 및 __init__ 함수를 재정의하여 생성자에 지정된 함수를 호출하고 클래스의 인스턴스에 값을 저장하십시오.

    스레드를 사용하지 않는 이유가 있습니까? 스레딩 클래스를 사용할 수 있습니다. finished () 함수 대신 isAlive ()를 사용하십시오. result () 함수는 스레드를 join ()하여 결과를 검색 할 수 있습니다. 그리고 가능한 경우 run () 및 __init__ 함수를 재정의하여 생성자에 지정된 함수를 호출하고 클래스의 인스턴스에 값을 저장하십시오.

  11. ==============================

    11.concurrent.futures (Python 3.2에서 추가됨)를 사용할 수 있습니다.

    concurrent.futures (Python 3.2에서 추가됨)를 사용할 수 있습니다.

    import time
    from concurrent.futures import ThreadPoolExecutor
    
    
    def long_computation(duration):
        for x in range(0, duration):
            print(x)
            time.sleep(1)
        return duration * 2
    
    
    print('Use polling')
    with ThreadPoolExecutor(max_workers=1) as executor:
        future = executor.submit(long_computation, 5)
        while not future.done():
            print('waiting...')
            time.sleep(0.5)
    
        print(future.result())
    
    print('Use callback')
    executor = ThreadPoolExecutor(max_workers=1)
    future = executor.submit(long_computation, 5)
    future.add_done_callback(lambda f: print(f.result()))
    
    print('waiting for callback')
    
    executor.shutdown(False)  # non-blocking
    
    print('shutdown invoked')
    
  12. ==============================

    12.프로세스를 사용할 수 있습니다. 영원히 (네트워킹과 같은) 사용하는 동안 그것을 사용하려면 다음과 같이하십시오.

    프로세스를 사용할 수 있습니다. 영원히 (네트워킹과 같은) 사용하는 동안 그것을 사용하려면 다음과 같이하십시오.

    from multiprocessing import Process
    def foo():
        while 1:
            # Do something
    
    p = Process(target = foo)
    p.start()
    

    한 번 실행하려는 경우 다음과 같이하십시오.

    from multiprocessing import Process
    def foo():
        # Do something
    
    p = Process(target = foo)
    p.start()
    p.join()
    
  13. from https://stackoverflow.com/questions/1239035/asynchronous-method-call-in-python by cc-by-sa and MIT license