-
Asyncio - async, awaitPython 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.
- asyncio.get_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:34Awaitable - 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 객체
- A 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을 넣어서 기본 스레드 풀을 사용합니다. 그리고 두 번째 인수에는 실행할 함수를 넣고 세 번째 인수부터는 실행할 함수에 들어갈 인수를 차례대로 넣어준다.
'Python' 카테고리의 다른 글
Python - Property (0) 2024.02.19 Flask - Celery - 비동기 처리하기 (0) 2022.02.07 Python Asyncio - 코루틴, 크롤링 (0) 2022.01.18 OOP - 상속,변수, 초기화- Crawling/Custom Exceptions (0) 2022.01.13 [TEST] 2.테스트 코드 작성하기 (0) 2021.10.24