[Python] Redis rq 를 이용한 간단한 비동기 작업 큐 Develop Tip

파이썬에서 비동기 작업 큐 라고 하면 가장 먼저 떠 오르는 것이 Celery 라는 것입니다.

그런데 위에 읽어보면 비동기 큐라기 보다는 "분산 작업 큐" 라는 것이 더 정확한 말입니다.

분산이라는 의미로 어떤 작업을 특정 큐에 넣으면 네트워크 환경에서 이를 여러 워커들이 다양한 우선순위를 갖고
이를 처리한다는 의미이지요.

그런데 최근에 이런 분산의 목적 보다는 정말로 단순한 작업 대기 큐로서 비동기 작업 큐가 필요하게 되었습니다.

간단히 찾아보니, RQ 라는 것이 있었습니다.

위의 홈페이지에 있는 것이 감이 잘 안잡혀 살펴보다가 원 소스에 있는 예제를 살펴보았습니다.

이 예제를 돌리는데 필요한 것은
redis 서버와 파이썬 redis, rq 모듈입니다.

맥에서는 간단히

$ brew install redis
(python2) $ pip install redis rq

라고 (VirtualEnv 환경에서) 설치했습니다.

우선 fib.py 라는 함수입니다.

간단한 피보나치 수열을 재귀호출로 계산하는 것입니다.
파이썬이 For loop 이나 재귀호출 등이 C나 Pypy에 비하여 많게는 40~50배까지 느리기 때문에
이렇게 붙였나 봅니다. (CPython, PyPy, ctypes 등 실행 비교 참조)

참고로 위와 같이 실행 함수는 별도 참조 모듈로 떼어 놓아야 합니다.

위의 함수를 enqueue에 놓았더니 worker가 참조하지 못하는 현상이 발생하더군요.
파이썬의 sys.path 에서 참조할 수 있는 절대경로에 놓아야 다른 위치에서 
worker 를 실행시켜도 참조가능함을 명심해야 합니다.

이제는 run_example.py

위와 같이 놓아 봅니다.
(PyCharm이 상대 경로의 모듈을 찾지 않기 때문에 from fib 부분이 경고가 뜨는데 실행에는 문제 없었습니다.)

위의 프로그램은 간단히 main 함수를 실행하면 Queue() 인스턴스를 얻어 20에서 39 까지는 정수 리스트를 이용하여
작업을 시작 q.enqueue(함수, 패러미터) 하여 놓고,
0.2 초 간격으로 무한 루프를 돌면서 큐에 들어간 작업이 종료 되었는가 확인하고 그 모든 결과가 아직 끝나지 않았으면 (None)
계속 루프를 도는 것입니다.

워커는 동시성이나 병렬성을 갖지 않는 단일 동작으로서 순서대로 작업을 처리하게 됩니다.

이제 워커의 소스 run_worker.py 를 보면,

로 정말 간단합니다. 아무것도 없이 디폴트 연결에 큐 인스턴스를 생성해서 해당 큐에 대하여 워커가 작업하는
슈도 코드 정도 입니다.

실제로 위의 프로그램을 실행 시켜도 되지만 

또는

$ rq worker 

라고 해도 잘 동작합니다. (CLI 명령이 같이 설치됩니다)

이제는 실행해 보는 시간입니다.

우선 
$ python run_worker.py 
워커부터 실행시켜 놓습니다.

이전에 언급한 것처럼

$ rq worker
와 동일합니다.

위에서 처럼 redis 큐에서 대기하고 있는 상황입니다.

이제는 실제 작업을 실행시키기 위하여

$ python run_example.py
라고 실행시키면,

위에처럼 이미 빨리 결과가 끝난 것도 있고 작업하고 있는 중 "(calculating)" 이라고 나오는 것도 있습니다.

이 상태에서의 worker 상황은

와 같이 나옵니다. 36번의 피보나치 작업을 하고 있습니다. 재미난 것은 결과는 500초 동안 보관된다는 것이네요.
(아마 설정에서 변경할 수 있을 듯 합니다.)

조금 더 기다리면,

73초 만에 모든 작업이 끝났습니다.

다시 워커를 확인하면,

모든 작업을 끝내고 Listening 하고 있다고 나오네요...

Flask에서 비동기로 작업을 시키고 바로 응답하고 이전 결과를 확인하는 등을 하는데 이용하면
편할 것 같습니다.

어느 분께는 도움이 되셨기를...

핑백

덧글

댓글 입력 영역

구글애드텍스트