수색…


코 루틴 및 위임 구문

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

Python 3.x 3.5

파이썬 3.5는 asyncawait 키워드를 도입했습니다. 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 에는 ThreadPoolExecutorProcessPoolExecutor 라는 두 가지 주요 유형의 Executor 가 있습니다. ThreadPoolExecutor 는 생성자를 통해 특정 수의 쓰레드를 수동으로 설정하거나 머신의 코어 수를 기본값으로 설정할 수있는 쓰레드 풀 5를 포함합니다. ThreadPoolExecutor 는 쓰레드 풀을 사용하여 할당 된 태스크를 실행하며 일반적으로 I / O 바운드 작업보다는 CPU 바운드 작업이 더 좋습니다. 그것에 할당 된 각 작업에 대해 새 프로세스를 생성하는 ProcessPoolExecutor 와 대조하십시오. ProcessPoolExecutor 는 picklable 인 작업과 매개 변수만을 사용할 수 있습니다. 가장 일반적으로 수행 할 수없는 작업은 개체의 메서드입니다. Executor 에서 객체의 메소드를 작업으로 스케쥴해야한다면 ThreadPoolExecutor 를 사용해야합니다.

UVLoop 사용

uvloopasyncio.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 내에서 함수를 호출하면 동시성이 없습니다. aiohttpasyncioasyncio 를 염두에두고 만들어졌습니다. 그 동시 루틴이 동시에 실행됩니다.

  • 병렬로 실행하고자하는 장기 실행 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