Python Language
Asyncio 모듈
수색…
코 루틴 및 위임 구문
파이썬 3.5+가 출시되기 전에 asyncio
모듈은 비동기 호출을 모방하는 생성자를 사용했기 때문에 현재 파이썬 3.5 릴리스와 다른 구문을 사용했습니다.
파이썬 3.5는 async
와 await
키워드를 도입했습니다. await func()
호출을 await func()
있는 괄호가 없다는 점에 유의하십시오.
import asyncio
async def main():
print(await func())
async def func():
# Do time intensive stuff...
return "Hello, world!"
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
Python 3.5 이전에는 @asyncio.coroutine
데코레이터가 코 루틴을 정의하는 데 사용되었습니다. 표현식의 yield는 생성자 위임에 사용되었습니다. yield from func()
의 yield from func()
주변의 괄호에 주목하십시오.
import asyncio
@asyncio.coroutine
def main():
print((yield from func()))
@asyncio.coroutine
def func():
# Do time intensive stuff..
return "Hello, world!"
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
다음은 두 함수를 비동기 적으로 실행하는 방법을 보여주는 예제입니다.
import asyncio
async def cor1():
print("cor1 start")
for i in range(10):
await asyncio.sleep(1.5)
print("cor1", i)
async def cor2():
print("cor2 start")
for i in range(15):
await asyncio.sleep(1)
print("cor2", i)
loop = asyncio.get_event_loop()
cors = asyncio.wait([cor1(), cor2()])
loop.run_until_complete(cors)
비동기 실행자
참고 : Python 3.5+ async / await 구문을 사용합니다.
asyncio
는 작업을 비동기 적으로 예약하기 위해 concurrent.futures
에서 찾은 Executor
객체의 사용을 지원합니다. 이벤트 루프에는 Executor
객체, Callable
및 Callable의 매개 변수를 취하는 run_in_executor()
함수가 있습니다.
Executor
위한 작업 스케줄링
import asyncio
from concurrent.futures import ThreadPoolExecutor
def func(a, b):
# Do time intensive stuff...
return a + b
async def main(loop):
executor = ThreadPoolExecutor()
result = await loop.run_in_executor(executor, func, "Hello,", " world!")
print(result)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
각 이벤트 루프는 또한 "기본"을 가지고 Executor
에 할당 할 수있는 슬롯 Executor
. Executor
를 할당하고 루프에서 작업을 예약하려면 set_default_executor()
메소드를 사용하십시오.
import asyncio
from concurrent.futures import ThreadPoolExecutor
def func(a, b):
# Do time intensive stuff...
return a + b
async def main(loop):
# NOTE: Using `None` as the first parameter designates the `default` Executor.
result = await loop.run_in_executor(None, func, "Hello,", " world!")
print(result)
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.set_default_executor(ThreadPoolExecutor())
loop.run_until_complete(main(loop))
concurrent.futures
에는 ThreadPoolExecutor
와 ProcessPoolExecutor
라는 두 가지 주요 유형의 Executor
가 있습니다. ThreadPoolExecutor
는 생성자를 통해 특정 수의 쓰레드를 수동으로 설정하거나 머신의 코어 수를 기본값으로 설정할 수있는 쓰레드 풀 5를 포함합니다. ThreadPoolExecutor
는 쓰레드 풀을 사용하여 할당 된 태스크를 실행하며 일반적으로 I / O 바운드 작업보다는 CPU 바운드 작업이 더 좋습니다. 그것에 할당 된 각 작업에 대해 새 프로세스를 생성하는 ProcessPoolExecutor
와 대조하십시오. ProcessPoolExecutor
는 picklable 인 작업과 매개 변수만을 사용할 수 있습니다. 가장 일반적으로 수행 할 수없는 작업은 개체의 메서드입니다. Executor
에서 객체의 메소드를 작업으로 스케쥴해야한다면 ThreadPoolExecutor
를 사용해야합니다.
UVLoop 사용
uvloop
은 asyncio.AbstractEventLoop
기반의 asyncio.AbstractEventLoop
구현입니다 ( asyncio.AbstractEventLoop
에서 사용). 99 %의 asyncio
기능을 지원하며 기존의 asyncio.EventLoop
보다 훨씬 빠릅니다. 현재 Windows에서 uvloop
사용할 수 없으며 pip install uvloop
하여 pip install uvloop
.
import asyncio
import uvloop
if __name__ == "__main__":
asyncio.set_event_loop(uvloop.new_event_loop())
# Do your stuff here ...
하나는 또한 설정하여 이벤트 루프 공장을 변경할 수 있습니다 EventLoopPolicy
에서 하나 uvloop
.
import asyncio
import uvloop
if __name__ == "__main__":
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
loop = asyncio.new_event_loop()
동기화 기본 요소 : 이벤트
개념
여러 코 루틴의 일정 을 동기화하려면 Event
를 사용하십시오.
간단히 말해서, 이벤트는 달리기에서 총을 쏜 것과 같습니다. 주자가 시작 블록에서 빠져 나갈 수 있습니다.
예
import asyncio
# event trigger function
def trigger(event):
print('EVENT SET')
event.set() # wake up coroutines waiting
# event consumers
async def consumer_a(event):
consumer_name = 'Consumer A'
print('{} waiting'.format(consumer_name))
await event.wait()
print('{} triggered'.format(consumer_name))
async def consumer_b(event):
consumer_name = 'Consumer B'
print('{} waiting'.format(consumer_name))
await event.wait()
print('{} triggered'.format(consumer_name))
# event
event = asyncio.Event()
# wrap coroutines in one future
main_future = asyncio.wait([consumer_a(event),
consumer_b(event)])
# event loop
event_loop = asyncio.get_event_loop()
event_loop.call_later(0.1, functools.partial(trigger, event)) # trigger event in 0.1 sec
# complete main_future
done, pending = event_loop.run_until_complete(main_future)
산출:
소비자 B 대기
소비자 A 대기
이벤트 설정
소비자 B가 실행 됨
소비자 A가 트리거 됨
간단한 웹 소켓
여기서 우리는 asyncio를 사용하여 간단한 echo websocket을 asyncio
. 우리는 서버 연결과 메시지 송수신을위한 코 루틴을 정의합니다. websocket의 통신은 이벤트 루프에 의해 실행되는 main
코 루틴에서 실행됩니다. 이 예는 이전 게시물 에서 수정되었습니다.
import asyncio
import aiohttp
session = aiohttp.ClientSession() # handles the context manager
class EchoWebsocket:
async def connect(self):
self.websocket = await session.ws_connect("wss://echo.websocket.org")
async def send(self, message):
self.websocket.send_str(message)
async def receive(self):
result = (await self.websocket.receive())
return result.data
async def main():
echo = EchoWebsocket()
await echo.connect()
await echo.send("Hello World!")
print(await echo.receive()) # "Hello World!"
if __name__ == '__main__':
# The main loop
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
asyncio에 대한 일반적인 오해
아마에 대한 가장 흔한 오해 asnycio
(별도의 스레드에서) 병렬로 차단 작업을 실행하므로 GIL (글로벌 통역 잠금)을 피하는하고 - 당신이 병렬로 모든 작업을 실행할 수 있다는 것입니다. 그것은하지 않습니다 !
asyncio
(과와 협력하여 구축 라이브러리 asyncio
) 코 루틴을 구축 : (공동) 호출 함수로 다시 제어 흐름을 산출 기능. 위의 예제에서 asyncio.sleep
에 유의하십시오. 이것은 '백그라운드에서'대기하고 호출 함수 ( await
와 함께 호출 될 때)로 제어 흐름을 되돌려주는 비 차단 코 루틴의 예입니다. time.sleep
은 블로킹 함수의 예입니다. 프로그램의 실행 흐름이 멈추고 time.sleep
이 끝난 후에 만 돌아갑니다.
실제 라이브 예제는 (당분간) 블로킹 기능만으로 구성된 requests
라이브러리입니다. asyncio
내에서 함수를 호출하면 동시성이 없습니다. aiohttp
에 asyncio
는 asyncio
를 염두에두고 만들어졌습니다. 그 동시 루틴이 동시에 실행됩니다.
병렬로 실행하고자하는 장기 실행 CPU 바인딩 작업이있는 경우
asyncio
사용할 수 없습니다 .threads
또는multiprocessing
가 필요threads
.당신은 IO-바인딩 작업이 실행이있는 경우, 당신은 동시에 사용하여 실행할 수 있습니다
asyncio
.