수색…


코 루틴 및 위임 구문

파이썬 3.5+가 출시되기 전에 asyncio 모듈은 비동기 호출을 모방하는 생성자를 사용했기 때문에 현재 파이썬 3.5 릴리스와 다른 구문을 사용했습니다.

Python 3.x 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.x 3.3 3.5

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())
Python 3.x 3.5

다음은 두 함수를 비동기 적으로 실행하는 방법을 보여주는 예제입니다.

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 .



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow