ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Asyncio - async, await
    Python 2022. 7. 2. 17:40

    * 최근 asyncio 를 api 테스트를 하면서 많이 사용하게 되었다. 사실상 지금은 부하테스트용도로 만들긴 했지만 실제 1초에 수만건 이상의 요청을 테스트하기 위한 다른 툴을 나중에 적용해보면 좋을듯 싶다.

    * 오늘 이 글의 작성 목적은 코드로 구현 하는 것보다는 Asyncio에 대한 히스토리, 개념 등에 조금 더 알고 이해한 내용에 대해 기록하는 것이다.

     

    * 파이썬 공식문서와 여러 블로그들을 읽었는데 블로그는 대부분의 내용이 겹쳤다. 파이썬 공식문서가 오히려 더 다양하게 설명되어 있고, 필요한 부분만 적을 예정이다.

     

    Asyncio - https://docs.python.org/3/library/asyncio.html

    • A library to write concurrent code using the async/await syntax.
    • Used as a foundation for multiple Python asynchronous frameworks that provide high-performance network and web-servers, database connection libraries, distributed task queues, etc.
    • Often, a perfect fit for IO-bound and high-level structured network code.

     

    이벤트 루프 - https://docs.python.org/3/library/asyncio-eventloop.html

    • The event loop is the core of every asyncio application. Event loops run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses.
    • Application developers should typically use the high-level asyncio functions, such as asyncio.run(), and should rarely need to reference the loop object or call its methods. This section is intended mostly for authors of lower-level code, libraries, and frameworks, who need finer control over the event loop behavior.
      • asyncio.get_event_loop()
        • Get the current event loop. If there is no current event loop set in the current OS thread, the OS thread is main, and set_event_loop() has not yet been called, asyncio will create a new event loop and set it as the current one.
        • Because this function has rather complex behavior (especially when custom event loop policies are in use), using the get_running_loop() function is preferred to get_event_loop() in coroutines and callbacks.
        • Consider also using the asyncio.run() function instead of using lower level functions to manually create and close an event loop.
     

    코루틴 - https://docs.python.org/ko/3.10/library/asyncio-task.html#id2

    • Coroutines declared with the async/await syntax is the preferred way of writing asyncio applications.
    • 코루틴을 동시에 실행하기 위해서는 태스크를 생성해야함 - asyncio.create_tast()
    >>> import asyncio
    
    >>> async def main():
    ...     print('hello')
    ...     await asyncio.sleep(1)  
    ...     print('world')
    
    >>> asyncio.run(main())
    hello
    world
    # 단순히 코루틴을 실행하는 것은 의미가 없음, 실행을 예약하는 것이 아님 -> 비동기로 작동하지 않음 1초후 world 출력
    
    
    import asyncio
    import time
    
    async def say_after(delay, what):
        await asyncio.sleep(delay)
        print(what)
    
    async def main():
        print(f"started at {time.strftime('%X')}")
    
        await say_after(1, 'hello')
        await say_after(2, 'world')
    
        print(f"finished at {time.strftime('%X')}")
    
    asyncio.run(main())
    
    started at 17:13:52
    hello
    world
    finished at 17:13:55
    
    # The asyncio.create_task() function to run coroutines concurrently as asyncio Tasks.
    async def main():
        task1 = asyncio.create_task(say_after(1, 'hello'))
    
        task2 = asyncio.create_task(say_after(2, 'world'))
    
        print(f"started at {time.strftime('%X')}")
    
        # Wait until both tasks are completed (should take around 2 seconds.)
        await task1
        await task2
    
        print(f"finished at {time.strftime('%X')}")
    
    started at 17:14:32
    hello
    world
    finished at 17:14:34

    Awaitable - await 표현식에 사용가능한 대상

    • 코루틴, 태스크, 퓨처으로 3가지
    • 코루틴 함수 = def 앞에 async 가 붙은 함수
    • 코루틴 객체: 코루틴 함수를 호출하여 반환되는 객체
    # 태스크 : Tasks are used to schedule coroutines concurrently, 
    # When a coroutine is wrapped into a Task with functions like asyncio.create_task() 
    # the coroutine is automatically scheduled to run soon
    import asyncio
    
    async def nested():
        return 42
    
    async def main():
        # Schedule nested() to run soon concurrently
        # with "main()".
        task = asyncio.create_task(nested())
    
        # "task" can now be used to cancel "nested()", or
        # can simply be awaited to wait until it is complete:
        await task
    
    asyncio.run(main())
    • Future 객체
      • Future is a special low-level awaitable object that represents an eventual result of an asynchronous operation. When a Future object is awaited it means that the coroutine will wait until the Future is resolved in some other place. Future objects in asyncio are needed to allow callback-based code to be used with async/await. Normally there is no need to create Future objects at the application level code.
    • urlopen이나 response.read 같은 함수(메서드)는 결과가 나올 때까지 코드 실행이 중단(block)되는데 이런 함수들을 블로킹 I/O(blocking I/O) 함수라고 부른다. 특히 네이티브 코루틴 안에서 블로킹 I/O 함수를 실행하려면 이벤트 루프의 run_in_executor 함수를 사용하여 다른 스레드에서 병렬로 실행시켜야 합니다. run_in_executor의 첫 번째 인수는 executor인데 함수를 실행시켜줄 스레드 풀 또는 프로세스 풀이며 여기서는 None을 넣어서 기본 스레드 풀을 사용합니다. 그리고 두 번째 인수에는 실행할 함수를 넣고 세 번째 인수부터는 실행할 함수에 들어갈 인수를 차례대로 넣어준다.

     

     

    https://chronosa.tistory.com/entry/python-asyncio%EB%A1%9C-boto3-%EC%8B%A4%ED%96%89%EC%8B%9C%ED%82%A4%EA%B8%B0-%EB%B6%80%EC%A0%9C-asyncio%EB%9E%80

Designed by Tistory.