본문 바로가기

Programming

[Python] gevent & monkey pathcing

 처음엔 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

 일단 처음엔 단순 for 문을 이용해 실험 

 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를 넣어 실행하는 것을 볼 수 있다.


*공부한지 얼마 되지 않아 정확하지 않을 수 있습니다. 위 글이 정확하지 않으면 댓글로 말씀해 주시면 감사하겠습니다.