3

클라이언트 (Ember.js)가 WebSocket (나는 Flask-SocketIO을 사용 중입니다)을 통해 서버와 통신하는 Python 웹 응용 프로그램이 있습니다. (tesseract 사용)Python과 Eventlet에서 다중 코어 사용

  • 클라이언트에서
  • OCR 들어오는 이미지 (graphicsmagick를 사용하여) 어떤 이미지 변환을 수행 : 는 별도로 웹 소켓 서버에서 백엔드은 언급 할 가치가 두 개 더 일을

    클라이언트는 엔티티가 데이터베이스에서 생성 된 이미지를 제출하고, ID가 이미지 변환 큐에 배치됩니다. 작업자는 그것을 잡고 이미지 변환을 수행합니다. 그런 다음 작업자는이를 OCR 대기열 작업자에 의해 처리 될 OCR 대기열에 넣습니다.

    지금까지 그렇게 좋았습니다. WS 요청은 별도의 스레드에서 동 기적으로 처리되며 (Flask-SocketIO는 Eventlet을 사용함) 무거운 계산 작업은 비동기 적으로 발생합니다 (별도의 스레드에서도 마찬가지 임).

    문제 : 전체 응용 프로그램이 라즈베리 파이 3에서 실행됩니다. 나는 4 개의 코어를 사용하지 않으면 내가 단지 한 ARMv8 코어 1.2 GHz의 클럭이 있습니다. 이것은 OCR을위한 힘이 거의 없습니다. 그래서 파이썬에서 다중 코어를 사용하는 방법을 알아보기로 결정했습니다. GIL의 문제에 대해 읽었지 만 multiprocessing에 대해서는 The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads.이라고되어 ​​있습니다. 정확히 내가 원했던 것. 그래서 나는 즉시

    from multiprocessing import Process 
    process = Process(target=heavy_computational_worker_thread) 
    process.start() 
    

    내가

    import multiprocessing 
    queue = multiprocessing.Queue() 
    

    from queue import Queue 
    queue = multiprocessing.Queue() 
    

    을 변경했다 그래서뿐만 아니라 멀티 코어에 의해 처리 될 필요가 큐에 의해

    from threading import Thread 
    thread = Thread(target=heavy_computational_worker_thread) 
    thread.start() 
    

    교체

    도 마찬가지입니다. 문제 : 큐와 스레드 라이브러리는 Eventlet별로 monkey patched입니다. 나는 스레드와 큐의 원숭이 패치 버전을 사용을 중지하고 큐에 접근 영원히 때 Eventlet 블록에 의해 시작 대신 다음 multiprocsssing에서 하나의 요청 스레드를 사용하는 경우.

    이제 내 질문 :

    내가이 응용 프로그램을 만들 수있는 방법은 별도의 코어에 OCR 및 이미지 변환이 할 수 있습니까?

    그게 가능하다면 웹 소켓 및 Eventlet을 계속 사용하고 싶습니다. 장점은 프로세스 간의 유일한 통신 인터페이스가 대기열이라는 것입니다. - 큐의 파이썬 구현을 사용하는 것이 아니라 I/O를 사용하지 : 이미했다

    아이디어. (| python3의 ocrqueue | python3의 imgconvqueue 예를 들어, python3 wsserver) 별도의 파이썬 프로세스로 모든 큐 노동자 시작 : 한 단계 더 간다 - 서로 다른 서브 프로세스가 에 액세스 할 예를 전용 레디 스하십시오.그렇다면 대기열과 데이터베이스에 대한 액세스가 비 블로킹이되도록해야합니다.

    가장 좋은 방법은 단일 프로세스를 유지하고 다중 처리와 함께 작동시키는 것입니다.

+0

Evenlet 라이브러리에 대해 잘 모르기 때문에 내 대답이 적용되지 않을 수도 있습니다. "메인"프로그램에서 멀티 스레딩을 사용하십시오. 해당 메인 애플리케이션의 각 "프로세스"내에서 "서브 프로세스"를 사용하여 서브 프로그램 (파이썬 프로그램이 파이썬 프로그램을 호출하는 경우 이상하게 보일지라도)을 호출하십시오. 이러한 하위 프로세스에서만 "Eventlet"라이브러리 (또는 프로세스 안전하지 않은 라이브러리)를 사용하십시오. 주 프로그램에서 사용하지 마십시오. "Queue"는 사용할 수 없지만 파일을 통해 데이터를 전달할 수 있습니다 (예 : 프로그램 A는 이미지 파일을 작성한 후 종료하고 프로그램 B는 시작하고이 파일을 읽습니다). –

답변

3

Eventlet는 멀티 패키지와 현재 호환되지 않는 사전에 대단히 감사드립니다. 이 작품에 대한 공개 문제가 있습니다 : https://github.com/eventlet/eventlet/issues/210.

귀하의 경우에 잘 작동한다고 생각되는 대안은 Celery를 사용하여 대기열을 관리하는 것입니다. Celery는 메시지 큐 (RabbitMQ 및 Redis가 모두 지원됨)를 통해 주 프로세스에서 제공되는 작업을 대기하는 작업자 프로세스 풀을 시작합니다.

셀 룰리 작업자는 eventlet을 사용할 필요가 없으므로 주 서버 만 수행하므로, eventlet에 의해 부과 된 제한없이 수행해야하는 모든 작업을 수행 할 수 있습니다.

이 방법을 탐색하는 데 관심이 있다면이 예제를 사용하는 완전한 예제가 있습니다 : https://github.com/miguelgrinberg/flack.

+0

감사합니다.이 작품은 매력과 같습니다. 지금 직면하고있는 유일한 문제는 전역 변수에서 socketio 인스턴스를 여러 프로세스에 걸쳐 공유 할 수 없다는 것입니다. 그러나이를 공유하기 위해 전용 저장소를 사용하거나 작업 기능에 변수를 제공하여 해결할 수 있어야합니다. – Schnodderbalken

+0

제가 답변에서 참조한 프로젝트를 참조하십시오. 작업자 프로세스에서 방출해야하는 경우 각 프로세스에서 socketio 인스턴스를 작성하십시오. 차이점은 셀러리 작업자의 socketio 인스턴스에는 Flask 앱 인스턴스가 연결되지 않아서 만 방출된다는 것입니다. 프로세스간에 아무 것도 공유 할 필요가 없으며 모든 통신은 메시지 대기열을 통해 수행됩니다. – Miguel

+0

https://github.com/miguelgrinberg/Flask-SocketIO/blob/master/docs/index.rst에서 설명하는 지침을 따랐습니다. message_queue = 'redis : //'와 함께 생성자를 사용하여 문제를 해결했습니다. :)이 방법으로 나는 socketio의 인스턴스 하나만 가지고 작업자 프로세스에서 방출 할 수있게했다. – Schnodderbalken