将多核与 Python 和 Eventlet 结合使用

Using multiple cores with Python and Eventlet

我有一个 Python 网络应用程序,其中有客户端 (Ember.js) communicates with the server via WebSocket (I am using Flask-SocketIO)。 除了 WebSocket 服务器之外,后端还做了两件值得一提的事情:

当客户端提交图像时,其实体将在数据库中创建,并将 id 放入图像转换队列中。工人抓住它并进行图像转换。之后工作人员将其放入 OCR 队列,由 OCR 队列工作人员处理。

到目前为止一切顺利。 WS 请求在单独的线程中同步处理(Flask-SocketIO 为此使用 Eventlet)并且繁重的计算操作异步发生(也在单独的线程中)。

现在的问题是:整个应用程序运行在 Raspberry Pi 3 上。如果我不使用它的 4 个内核,我只有 一个主频为 1.2 GHz 的 ARMv8 内核。这对于 OCR 来说是非常微弱的力量。所以我决定找出如何使用 Python 的多核。虽然我读到 GIL) I found out about multiprocessing 的问题,但它说 The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads.。正是我想要的。所以我立即更换了

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

来自

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

队列也需要由多核处理所以我不得不改变

from queue import Queue
queue = multiprocessing.Queue()

import multiprocessing
queue = multiprocessing.Queue()

还有。有问题:队列和线程库由 Eventlet monkey patched。如果我停止使用 Thread 和 Queue 的猴子修补版本并使用来自 multiprocsssing 的版本,那么在访问队列时由 Eventlet 启动的请求线程将永远阻塞。

现在我的问题是:

有什么方法可以让这个应用程序在单独的内核上进行 OCR 和图像转换吗?

如果可能的话,我想继续使用 WebSocket 和 Eventlet。我的优势是进程之间唯一的通信接口是队列。

我已有的想法: - 不使用队列的 Python 实现,而是使用 I/O。例如,不同子进程将访问的专用 Redis - 更进一步:将每个队列工作者作为一个单独的 Python 进程启动(例如 python3 wsserver | python3 ocrqueue | python3 imgconvqueue)。然后我必须确保自己对队列和数据库的访问是非阻塞的

不过,最好的办法是保留单个进程并使其与多进程一起工作。

非常感谢您

Eventlet 当前与多处理包不兼容。这项工作有一个未解决的问题:https://github.com/eventlet/eventlet/issues/210.

我认为适合您的情况的替代方法是使用 Celery 来管理您的队列。 Celery 将启动一个工作进程池,等待主进程通过消息队列提供的任务(支持 RabbitMQ 和 Redis)。

Celery 工作人员不需要使用 eventlet,只有主服务器需要,因此这使他们可以自由地做他们需要做的任何事情,而不受 eventlet 强加的限制。

如果您有兴趣探索这种方法,我有一个使用它的完整示例:https://github.com/miguelgrinberg/flack