async def
로 만든 코루틴은 네이티브 코루틴이라고 함async def
키워드는 파이썬 3.6이상부터 사용 가능함import asyncio
# async def로 네이티브 코루틴을 만듦
async def hello():
print("Hello, World!")
if __name__ == "__main__":
loop = asyncio.get_event_loop() # 이벤트 루프를 얻음
loop.run_until_complete(hello()) # 네이티브 코루틴 객체인 hello()가 끝날 때까지 기다림
loop.close() # 이벤트 루프를 닫음(relase)
HleHello, World!
await
뒤에 코루틴 객체, 퓨쳐객체, 태스크 객체를 지정하면 해당 객체가 끝날 때까지 기다린 뒤 결과를 반환함변수 = await 코루틴객체
await
는 단어 뜻 그대로 특정 객체가 끝날 때까지 기다림await
키워드는 파이썬 3.5이상 부터 사용 가능, 3.4에서는 yeild fromd을 사용네이티브 코루틴 안
에서만 사용할 수 있음from time import time
from urllib.request import Request, urlopen
if __name__ == "__main__":
urls = ["https://www.google.co.kr/search?q=" + item
for item in ["apple", "pear", "grape", "pineapple", "orange", "strawberry"]]
start_time = time()
results = []
for url in urls:
request = Request(url, headers = {"User-Agent": "Mozilla/5.0"}) # UA가 없으면 403 Forbidden 에러 발생
response = urlopen(request)
page = response.read()
results.append(len(page))
print(results)
end_time = time()
print(f"실행 시간: {round(end_time - start_time, 3)}초")
[81098, 148269, 101121, 75948, 149267, 146069]
실행 시간: 6.078초
from time import time
from urllib.request import Request, urlopen
import asyncio
async def fetch(url):
request = Request(url, headers={"User-Agent": "Mozilla/5.0"})
response = await loop.run_in_executor(None, urlopen, request)
page = await loop.run_in_executor(None, response.read)
return len(page)
async def main():
items = [asyncio.ensure_future(fetch(url)) for url in urls]
results = await asyncio.gather(*items)
print(results)
if __name__ == "__main__":
urls = ["https://www.google.co.kr/search?q=" + item
for item in ["apple", "pear", "grape", "pineapple", "orange", "strawberry"]]
start_time = time()
loop = asyncio.get_event_loop()
loop.run_until_complete(main()) # main이 끝날 때 까지 기다림
loop.close()
end_time = time()
print(f"실행 시간: {round(end_time - start_time, 3)}초")
[81097, 148258, 101164, 75948, 149267, 150893]
실행 시간: 1.333초
6초에서 1.3초로 실행시간이 약 78% 빨라진 것을 볼 수 있다.
async def fetch(url):
request = Request(url, headers={"User-Agent": "Mozilla/5.0"})
response = await loop.run_in_executor(None, urlopen, request)
page = await loop.run_in_executor(None, response.read)
return len(page)
urlopen()이나 response.read() 같은 함수는 결과가 나올 때 까지 코드 실행이 중단(block)되는데 이런 함수들을 Blocking I/O 함수라고 부름
네이티브 코루틴 안에서 Blocking I/O 함수를 실행하려면 이벤트 루프의 run_in_executor()함수를 사용하여 다른 스레드에서 병렬로 실행시켜야 함
run_in_executor()의 첫 번재 인수(parameter)는 executor인데 함수를 실행시켜줄 스레드 풀 또는 프로세스 풀임
이벤트루프.run_in_executor(None, 함수, 인수1, 인수2, 인수3)
run_in_executor()도 네이티브 코루틴이므로 await로 실행한 뒤 결과를 가져옴
async def main():
items = [asyncio.ensure_future(fetch(url)) for url in urls]
results = await asyncio.gather(*items)
print(results)
태스크객체 = asyncio.ensure_future(코루틴객체 또는 퓨처객체)
변수 = await asyncio.gather(코루틴객체1, 코루틴객체2)
asyncio.gather()는 리스트가 아닌 위치 인수로 객체를 받으므로 태스크 객체를 리스트로 만들었다면 asyncio.gather(*items)와 같이 리스트를 언패킹(unpacking)해서 넣어줌
asyncio.gather()도 코루틴이므로 await로 실행한 뒤 결과를 가져옴
⚠️ 멀티스레드로 동작하기 때문에 반환되는 리스트 결과값이 *items로 전달해준 객체의 순서와 같지 않을 수 있다.