generator coroutine 사용

import types


# generator base coroutine을 사용한 비동기 로직 yield로 제어권을 서로 계속 넘겨준다.


@types.coroutine

def switch():

    yield


async def coro1():

    print('C1: Start')

    await switch()

    print('C1: a')

    await switch()

    print('C1: end')


async def coro2():

    print('C2: Start')

    await switch()

    print('C2: a')

    await switch()

    print('C2: end')


def run(cors):

    while cors:

        print("코루틴이 다시 시작할 지점을 기억하고 있다.")

        for corou in [c1,c2]:

            corou.send(None)


c1 = coro1()

c2 = coro2()

task = [c1, c2]


run(task)


asyncio 사용

import asyncio


async def co1():

    print('코루틴 1 실행')

    await asyncio.sleep(5)

    print('코루틴 1 재개')

    return '코루틴 1 종료'


async def co2():

    print('코루틴 2 실행')

    await asyncio.sleep(2)

    print('코루틴 2 재개')

    return '코루틴 2 종료'


async def main():

    tasks = [co1(), co2()]

    result = await asyncio.gather(*tasks)

    print(result)


    #tasks = [co1(), co2()]

    #for res in await asyncio.gather(*tasks):

    #    print(f'서브 스레드 종료 {res}')


    #co1_r = await co1() 기다림1

    #co2_r = await co2() 기다림1 끝나고 다시 기다림2

    #print(co1_r, co2_r)


    #loop = asyncio.get_event_loop() # 코루틴 실행과정을 위한 무한루프

    #co1_r = loop.create_task(co1()) # 기다리지 않고 실행

    #co2_r = loop.create_task(co2()) # 기다리지 않고 실행 됐기 때문에 메인 스레드가 종료되서 코루틴 1 실행, 코루틴 2 실행만 출력됨


asyncio.run(main())



*concurrent.futures(다중 스레드, 비동기/Non-block 방식)

executor.submit(함수, 매개변수) -> 별도의 스레드로 실행중인 future 객체를 얻음 (메인 스레드는 동작중)

future.result() -> 결과를 얻음 (아직 실행중이라면 메인 스레드가 결과를 받을때 까지 중지할 수 있다)

futures.as_completed() -> 완료되거나 이셉션이 발생한 future들을 순차적으로 받을 수 있다(대게 포문)


*asyncio(단일 스레드, 비동기/Non-block 방식)

이러한 대기시간 동안에 해당 작업 외에 다른 작업으로의 전환을 단일 스레드에서 처리할 수 있는 기반 기술들은 파이썬의 코루틴이다.

I/O 처리를 기다리는 역할을 코루틴에게 위임하고, 그 시간 동안 다른 코루틴을 이용해서 별도의 작업을 또 비동기로 처리할 수 있다.


task -> asyncio.future의 자식 클래스이며 concurrent.future.Future와 거의 같은 API를 제공 / 코루틴을 감싼 객체

await -> 서브 코루틴에 제어권을 주는것 await 없이 함수를 호출하면 호출은 했지만 제어권이 없어 런타임 오류발생

-> 메인 함수에서 await를 추가해서 호출하거나 asyncio.create_task()로 이벤트 루프에 코루틴 객체를 전달하여 실행을 등록


asyncio.get_event_loop() -> 루틴을 모아놓을 빈 리스트 [] 생성

-> send()를 반복적으로 끊임없이 호출하여 멈춰있는 코루틴을 실행시키는 역할

asyncio.create_task() -> 실행시킬 코루틴을 리스트에 등록(예약) schedule, 이벤트 루프에 등록과 같음

loop.run_until_complete() -> 코루틴 실행(단일)

loop.run_in_executor(pool, func) -> blocking 함수를 awaitable하게 돌릴 수 있도록 task로 만들어주는 함수

-> 기본 executor 또는 thread,process executor에서 할지 pool을 넣어서 지정해줄 수 있다

asyncio.gather(*aws) -> 비동기로 두 개 이상의 코루틴을 등록할 때 사용, unpacked 형태로 넣어주어야 한다.


파이썬 3.7 이상은 asyncio.run() 이걸로 이벤트 루프를 만들고 코루틴을 실행할 수 있음 (루프 생성을 안해줘도 된다는 뜻)


이벤트 루프가 태스크들을 여러개 가지고 있고 한번에 한 태스크들씩 실행하는데

태스크에 감싸진 코루틴이 퓨처 객체(실행흐름)가 값을 리턴해 줄 때까지 대기중이라면

이벤트 루프는 다른 태스크를 실행시키거나 I/O작업을 수행한다.