Post

(python) ( coroutine / Task )와 비동기 모듈

coroutine

코루틴이란 ? 각 루틴이 종속적인 관계 아닌(caller, callee 관계인 subroutine이 아닌) 대등한 관계로, 서로를 순차적으로 호출하도록 되어 있는 함수

~3.4 에서는 제너레이터를 사용해 코루틴을 구현

제너레이터는 어디까지 실행했는지를 기억했다가 나중에 다시 그 부분부터 실행되기 때문에, 이를 Future와 결합하면 코루틴을 구현하기 용이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
## next(c) 한 번 호출 시 다음 yield까지 실행.
## 즉 아래 함수는 next(c)를 3번 호출 가능
def coro():


## 밑줄 부분을 실행("yield1" 반환)하고 첫 번째 멈춤. 즉 hello = ???는 아직 실행 전.


hello =
yield "yield1"yield hello    # hello를 반환하고 두 번째 멈춤
print("end")
## 세 번째 next에서 종료되며 StopIteration

  c = coro()
   print(next(c))          # 첫 번째 yield까지 실행. yield1을 반환


## send()로 yield 표현식에 값을 전달할 수 있다.
print(c.send("World"))  # hello = {"World"} & yield hello를 실행.


next(c)    # end 출력하고 종료되면서 StopIteration
  • 이렇게 코루틴은 yield를 만나면 제어권을 넘기면서 실행한다.
  • 지금은 Coroutine을 직접 main에서 불러주었지만, 코루틴들을 EventLoop 위에서 실행하도록 할 수 있다. (asyncio에서는 이를 API로 지원한다.)
    • 간단한 EventLoop는 아래와 같은 형식이 된다.
1
2
3
4
5
class EventLoop(Queue):
def start(self):
while True:
coro = self.get()
coro()
3.4 generator based coroutine
1
2
3
4
5
6
7
8
9
10
11
12
import asyncio


@asyncio.coroutine
def cortn():
yield from asyncio.sleep(1.0)
print('Hello, world!')


loop = asyncio.get\_event\_loop()
loop.run\_until\_complete(cortn())
loop.close()

Note ) await == yield from 이다.

asyncio ( HTTP : aiohttp )
  • 단일 thread에서 코드가 진행되므로 CPU에서 context switching이 일어나지 않기 때문에 CPU 코어 수준의 병렬 처리는 일어나지 않는다. (단일 코어에서의 context switching을 말한다. [GIL]) 그러나 각 코드는 이벤트 루프 위에서 제어권을 주고 받으며 돌아가기 때문에 동시에 실행되는 것 처럼 보인다.
  • await를 만나면 해당 코루틴의 작업이 완료될 때 까지 기다리게 되지만 제어권을 넘기게 되므로 thread 자체가 중단되지는 않는다.
This post is licensed under CC BY 4.0 by the author.