반응형
파이썬 코루틴(coroutine)
파이썬 비동기 함수는 코루틴 함수로 만들 수 있다.
코루틴은 진입점과 탈출점이 여러 개가 있는 함수라고 할 수 있다.
파이썬 코루틴 공식 홈페이지에 있는 예제를 살펴보면 asyncio API에 대해 설명하고 있다.
다음 코드는 "hello"를 인쇄하고 1초를 기다린 다음 "world"를 인쇄한다.
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
asyncio.run(main())
코루틴 함수를 만들기 위해는 함수 앞에 async 키워드를 붙여주면 된다.
await는 어웨이터블 객체만 사용할 수 있으며, 코루틴 내에서 다른 코루틴을 호출하고 결과를 받을 때 사용된다.
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())
약 3초가 걸린다.
위의 코드는 단순 코루틴을 호출하는 것이지 여러 코루틴을 동시에 실행하는 것은 아니다.
asyncio.create_task()로 태스크를 실행하도록 예약해야 한다.
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
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')}")
# await say_after(1, 'hello')
# await say_after(2, 'world')
await task1
await task2
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
2초로 줄어드는 걸 볼 수 있다.
asyncio.gather로 여러 태스크를 한번에 등록할 수 있다.
다른 예제를 살펴보자.
네이버, 구글, 인스타그램을 각각 10번씩 요청해서 그에 대한 응답을 가져오는데, 약 10초정도 소요된다.
import requests
import time
def fetcher(session, url):
with session.get(url) as response:
return response.text
def main():
urls = ["https://naver.com", "https://google.com",
"https://instagram.com"] * 10
with requests.Session() as session:
result = [fetcher(session, url) for url in urls]
print(result)
if __name__ == "__main__":
start = time.time()
main()
end = time.time()
print(end - start)
위의 코드를 비동기 코드로 변경해보자.
우선 aiohttp 패키지가 필요하므로 이를 pip를 이용해서 설치하고 변경하면 아래와 같다.
import aiohttp
import time
import asyncio
async def fetcher(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://naver.com", "https://google.com", "https://instagram.com"] * 10
async with aiohttp.ClientSession() as session:
result = await asyncio.gather(*[fetcher(session, url) for url in urls])
print(result)
if __name__ == "__main__":
start = time.time()
asyncio.run(main())
end = time.time()
print(end - start)
약 3초정도 걸린다.
적절한 때에 비동기 형태로 코드를 구성하면 많은 시간을 단축할 수 있다.
References:
https://docs.python.org/ko/3/library/asyncio-task.html
https://github.com/amamov/teaching-async-python
반응형
'Programming > Python' 카테고리의 다른 글
PyAutoGUI를 통한 마우스 키보드 자동화 (0) | 2022.03.21 |
---|---|
파이썬 Slacker를 이용한 Slack(슬랙) bot 사용 (0) | 2021.01.31 |
파이썬 datetime으로 파일명 생성 (0) | 2020.12.20 |
파이썬 comprehension, lambda, zip (0) | 2020.12.02 |
파이썬 PyQt 모듈 (0) | 2020.11.29 |