# async1.py
import asyncio
async def add(x: int) -> int:
return x + 1
def main():
ret = add(1)
print(f"ret = {ret}")
if __name__ == "__main__":
main()비동기
비동기 함수 정의
async키워드를 함수 앞에 붙이면 비동기 함수가 됨- 비동기 함수를 호출하면 그 함수를 실행하는게 아니고 해당 함수에 대한 코루틴(coroutine)을 출력
- 함수 코루틴은 그 함수를 앞으로 실행하겠다는 약속에 지나지 않음
$ python async1.pyret = <coroutine object add at 0x000001BDADBEE800>
~\Work\book\book_python\lang\async1.py:11: RuntimeWarning: coroutine 'add' was never awaited
main()
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
비동기 함수의 동기화 실행
- 비동기 함수를 동기 함수처럼 실행하려면
- 비동기 함수를 호출할 때
await키워드를 붙여서 호출하고 - 호출한 함수도 비동기 함수이여야 하며
- 최초 호출한 비동기 함수의 코루틴을
asyncio.run함수에 인수로 넘겨야
- 비동기 함수를 호출할 때
- 비동기 함수를
await방식으로 실행하면 실행 중 다른 함수를 동시 실행 불가능
- 1
-
asyncio.run함수를 사용하기 위해 asyncio 패키지 임포트 - 2
-
await호출을 하는 main 함수도async키워드가 있어야 함 - 3
-
await키워드를 붙여서 호출 - 4
-
main 함수 자체가 아니라 main 함수가 반환하는 코루틴을
asyncio.run함수에 넣어야 함
$ python async2.pyret = 2
task 객체
asyncio.create_task함수에 비동기 함수의 코루틴을 넣어 만든 task 객체를 사용하면 동시 실행 가능- task 객체를 생성하는 순간 비동기 함수의 실행이 예약(스케줄링)되고 호출한 함수의 코드가 계속 실행됨
- 다른 task 객체를 생성하면 그 비동기 함수도 실행 예약(스케줄링)
- 호출한 함수가 await 키워드를 만나면 해당 task가 실행완료될 때까지 대기함
- 만약 이미 완료된 상태면 바로 다음 라인으로 실행
- 여러 task가 스케줄링되어 있는 경우 한 번에 하나의 task만 실행됨
- task 실행중 sleep 또는 await를 만나면 해당 task는 실행을 중단하고 스케줄링된 다른 task 실행
- 비동기 함수에는 time.sleep 함수 대신 asyncio.sleep 함수를 사용해야 함
- asyncio.sleep 함수도 비동기 함수이므로 await 키워드로 호출해야 함
# async3.py
import asyncio
async def task_fun(x: int) -> None:
print(f"start task{x}")
await asyncio.sleep(x)
print(f"finish task{x}")
async def main():
1 task = asyncio.create_task(task_fun(1))
print(f"task = {task}")
2 ret = await task
print(f"ret = {ret}")
if __name__ == "__main__":
asyncio.run(main())- 1
-
asyncio.create_task함수로 task 객체를 만든다 - 2
- task 개체에 대해서 await 호출
$ python async3.pytask = <Task pending name='Task-2' coro=<task_fun() running at ~\Work\book\book_python\lang\async3.py:3>>
start task1
finish task1
ret = None
- 다음 코드는 3개의 task를 동시 실행하는 예시
- task3, task2, task1 순서로 스케줄링
- 처음 나타나는 await task3 라인에서 main 함수는 멈추고 스케줄링된 task가 실행 시작
- task3 실행중 sleep을 만나면 task3는 일시 정지하고 task2 또는 task1이 실행 (순서는 미정)
- 만약 task2이 실행되었다고 가정하고 실행중 sleep을 만나면 task2는 일시 정지하고 task1이 실행
- 이 코드에서는 await task3 이 완료된 시점에서는 task1과 task2도 이미 완료된 상태이므로 await task2, await task1 이 사실상 의미가 없음
# async4.py
import asyncio
async def task_fun(x: int) -> None:
print(f"start task{x}")
await asyncio.sleep(x)
print(f"finish task{x}")
async def main():
task3 = asyncio.create_task(task_fun(3))
task2 = asyncio.create_task(task_fun(2))
task1 = asyncio.create_task(task_fun(1))
ret = await task3
ret = await task2
ret = await task1
if __name__ == "__main__":
asyncio.run(main())$ python async4.pystart task3
start task2
start task1
finish task1
finish task2
finish task3
- 실제로 await task2, await task1 라인을 없애도 정상 동작함
# async5.py
import asyncio
async def task_fun(x: int) -> None:
print(f"start task{x}")
await asyncio.sleep(x)
print(f"finish task{x}")
async def main():
task3 = asyncio.create_task(task_fun(3))
task2 = asyncio.create_task(task_fun(2))
task1 = asyncio.create_task(task_fun(1))
ret = await task3
if __name__ == "__main__":
asyncio.run(main())$ python async5.pystart task3
start task2
start task1
finish task1
finish task2
finish task3
- 하지만 다른 라인을 없애고 await task1 라인만 남기면 task2, task3이 끝날때까지 기다리지 않고 종료
# async6.py
import asyncio
async def task_fun(x: int) -> None:
print(f"start task{x}")
await asyncio.sleep(x)
print(f"finish task{x}")
async def main():
task3 = asyncio.create_task(task_fun(3))
task2 = asyncio.create_task(task_fun(2))
task1 = asyncio.create_task(task_fun(1))
ret = await task1
if __name__ == "__main__":
asyncio.run(main())$ python async6.pystart task3
start task2
start task1
finish task1