asyncio(Asynchronous I/O)는 비동기 프로그래밍을 위한 모듈
-> CPU와 I/O를 병렬로 처리하게 함
동기(synchronous) 처리는 특정 작업이 끝나면 다음 작업을 처리하는 순차처리 방식
비동기(asynchronous) 처리는 여러 작업을 처리하도록 예약한 뒤작업이 끝나면 결과를 받는 방식
asyncio 사용법
- async def 는 python3.5 이상 부터 가능
- 비동기 함수를 python에서는 코루틴(coroutine)이라고 부름
async def do_async():
pass
# do_async() # <coroutine object do_async at 0x1038de710>
비동기 함수는 일반적으로 async로 선언된 다른 비동기 함수 내에서 await 키워드를 붙여 호출함
async로 선언되지 않은 일반 동기 함수 내에서 비동기 함수를 호출하려면 asyncio라이브러리의 이벤트 루프를 사용
loop = asyncio.get_event_loop()
loop.run_until_complete(main_async())
loop.close()
예시1)
import asyncio
async def hello(): # async def로 네이티브 코루틴을 만듦
print('Hello, world!')
loop = asyncio.get_event_loop() # 이벤트 루프를 얻음
loop.run_until_complete(hello()) # hello가 끝날 때까지 기다림
loop.close() # 이벤트 루프를 닫음
await 사용법
- await는 python3.5 이상 부터 가능
- await 뒤에 코리틴 객체/퓨처 객체/태스크 객체를 지정
- 해당 객체가 끝날 때 까지 기다린뒤 결과를 반환
- 특정 객체가 끝날 때까지 기다림
- await는 네이티브 코루틴 안에서만 사용 가능
import asyncio
async def add(a, b):
print('add: {0} + {1}'.format(a, b))
await asyncio.sleep(1.0) # 1초 대기. asyncio.sleep도 네이티브 코루틴
return a + b # 두 수를 더한 결과 반환
async def print_add(a, b):
result = await add(a, b) # await로 다른 네이티브 코루틴 실행하고 반환값을 변수에 저장
print('print_add: {0} + {1} = {2}'.format(a, b, result))
loop = asyncio.get_event_loop() # 이벤트 루프를 얻음
loop.run_until_complete(print_add(1, 2)) # print_add가 끝날 때까지 이벤트 루프를 실행
loop.close() # 이벤트 루프를 닫음
결과
add: 1 + 2
print_add: 1 + 2 = 3
퓨처(asyncio.Future)는 미래에 할 일을 표현하는 클래스인데 할 일을 취소하거나 상태 확인, 완료 및 결과 설정에 사용
태스크(asyncio.Task)는 asyncio.Future의 파생 클래스이며 asyncio.Future의 기능과 실행할 코루틴의 객체를 포함하고, 코루틴의 실행을 취소하거나 상태 확인, 완료 및 결과 설정에 사용
비동기로 웹 페이지 가져오기
1. 일반
from time import time
from urllib.request import Request, urlopen
urls = ['https://www.google.co.kr/search?q=' + i
for i in ['apple', 'pear', 'grape', 'pineapple', 'orange', 'strawberry']]
begin = time()
result = []
for url in urls:
request = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) # UA가 없으면 403 에러 발생
response = urlopen(request)
page = response.read()
result.append(len(page))
print(result)
end = time()
print('실행 시간: {0:.3f}초'.format(end - begin))
- 결과
[89590, 88723, 88802, 90142, 90628, 92663]
실행 시간: 8.422초
2. asyncio
from time import time
from urllib.request import Request, urlopen
import asyncio
urls = ['https://www.google.co.kr/search?q=' + i
for i in ['apple', 'pear', 'grape', 'pineapple', 'orange', 'strawberry']]
async def fetch(url):
request = Request(url, headers={'User-Agent': 'Mozilla/5.0'}) # UA가 없으면 403 에러 발생
response = await loop.run_in_executor(None, urlopen, request) # run_in_executor 사용
page = await loop.run_in_executor(None, response.read) # run in executor 사용
return len(page)
async def main():
futures = [asyncio.ensure_future(fetch(url)) for url in urls]
# 태스크(퓨처) 객체를 리스트로 만듦
result = await asyncio.gather(*futures) # 결과를 한꺼번에 가져옴
print(result)
begin = time()
loop = asyncio.get_event_loop() # 이벤트 루프를 얻음
loop.run_until_complete(main()) # main이 끝날 때까지 기다림
loop.close() # 이벤트 루프를 닫음
end = time()
print('실행 시간: {0:.3f}초'.format(end - begin))
- 결과
[89556, 88682, 89925, 90164, 90513, 93965]
실행 시간: 1.737초
해석
- urlopen이나 response같은 메서드는 결과가 나올 때까지 코드 실행이 중단 됨
이러한 함수를 blocking I/O 함수라고 부름
'SW ENGINEERING > Python' 카테고리의 다른 글
파이썬 코딩의 기술TIP 5일차 (0) | 2021.06.07 |
---|---|
파이썬 코딩의 기술TIP 4일차 (0) | 2021.06.06 |
파이썬 코딩의 기술TIP 3일차 (0) | 2021.06.03 |
파이썬 코딩의 기술TIP 2일차 (0) | 2021.06.02 |
파이썬 코딩의 기술TIP 1일차 (0) | 2021.06.01 |
최근댓글