(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.