처음엔 gevent를 이용해 spawn과 join만 이용하면 모든 task들이 Non-Blocking 형태로 진행되고, spawn & join을 쓰지 않고 monkey patching만 하면 raw_socket들이 모두 비동기 형식으로 진행되는줄 알았다.(gevent에 대해 안지 얼마 되지 않아서 개념에 대한 이해도가 부족했다)
gevnet와 monkey patching을 이때까지 잘 사용해 왔는데 그럼 spawn & join 사용하는것과 monkey patching을 하는 것에 어떤 차이점이 있는지 생각을 하게 됐고, 이에 대해 여러 실험을 해보다 보니 잘못 이해하고 있었다는 것을 알 수 있었다.
결론을 먼저 적어보면,
- gevent는 단순하게 spawn & join만 사용하면 Non-Blocking이 되는 것이 아니다.
- event loop를 실행하는 Task 함수들이 코-루틴 형식으로 만들어져야 gevent가 제대로 실행된다.
- monkey patching을 하면 socket의 send & recv 함수가 override 되어 코-루틴 형식으로 변경된다(소켓만이 아닌 스레드 등도 마찬가지)
1. 단순 time.sleep을 이용해 gevent spawn & join
gevent spawn & join을 이용한 실험
똑같이 10초가 걸린것을 볼 수 있다.
2. gevent.sleep(코-루틴 형식)을 이용해 gevent spawn & join
time.sleep()을 gevent.sleep()으로 바꿈으로써 Non-Blocking으로 실행되었고 총 수행 시간은 1초가 걸린것을 볼 수 있다.
*Extra(Pool & Map)
gevent에는 pool 클래스가 존재한다. Blocking에 걸릴 때마다 다음 Task로 바로 넘어가는 것이 아닌 정해놓은 Concurrency Size 까지만 동시 처리하고, pool이 가득차면 더이상 진행을 하지 않는 것이다.
위 코드와 같이 Concurrency Size를 5로 할당하니 Task 0~4까지 한번에 실행하고 완료되면 5~9까지 다시 실행하는 것을 볼 수 있다.
단순 pool & spawn & join 외에도 pool에는 map이라는 함수가 존재하는데 위처럼 pool에 있는 모든 Task가 다 실행될 때까지 기다리는 것이 아닌 pool의 Task 중 하나가 완료되면 다른 Task를 넣어 실행 하는 것이다.
단순히 1초로만 해서는 알수가 없어 0~2초 사이 임의 값을 sleep하는 것으로 바꾸었다. 결과를 보면 알 수 있듯이, 2, 3 Task가 완료되어 pool이 비게 되면 바로 5, 6 Task를 넣어 실행하는 것을 볼 수 있다.
*공부한지 얼마 되지 않아 정확하지 않을 수 있습니다. 위 글이 정확하지 않으면 댓글로 말씀해 주시면 감사하겠습니다.
'Programming' 카테고리의 다른 글
[Python] Flask & Nginx & Gunicorn 연결하기 (0) | 2015.04.04 |
---|---|
[Python] Flask & Socket IO 웹 소켓을 이용한 채팅 (3) | 2015.02.03 |
[Python] gevent & mechanize, asynchronous Scraping (1) | 2015.01.24 |
node.js로 블로그 만들기 <<1>> (2) | 2014.12.01 |
[Python] Beautiful Soup과 smtp lib 이용해 게시판 파싱 & 메일 (0) | 2013.10.30 |