Python 多线程服务器和与 Android 客户端的异步 websocket 通信
Python multithreaded server and asynchronuous websocket communication with Android clients
我有一个 Android 客户端应用程序,它向 Python 中的服务器发送一些数据,其中 Python 服务器应该 运行 耗时很长operation/computation 和 return 结果给客户端。
为此,我最初开始在服务器端使用 Python 的 Flask,在客户端使用 asynchronous android http library 通过 http POST 发送数据。但是,我很快注意到这不是要走的路,因为服务器上的计算需要时间,这会导致客户端出现超时错误等问题
然后,我开始在客户端使用Tornado's Websockets on the server side, and an android library for websockets。然而,第一个主要问题是,当服务器正在 运行ning 给定客户端的耗时操作时,其他潜在客户端需要等待......而且让 tornado 工作似乎有点痛苦在多线程设置中(因为它最初计划是单线程的)。另一个小问题是,如果客户端在服务器正在处理他的请求时掉线,那么当他重新连接时,客户端可能永远得不到结果。
因此,我想问一下,如果我想使用异步多线程 Python 服务器进行这样的设置,我是否有任何解决方案或建议使用什么? cpu 使用来自客户端的数据进行计算,而无需让其他潜在客户端等待轮到他们;并有可能使客户端在连接回来时能够从服务器获取结果。
首先,如果您要在后端执行 cpu-繁重的 操作,您 [很可能] 需要 运行它在单独的 进程 中。不在 thread/coro/etc 中。原因是 python 有时仅限于单线程(您可以阅读有关 GIL 的更多信息)。在多线程中执行 cpu 繁重的操作可为您的后端提供一些可用性,但会影响整体性能。
Simple/old 解决方案 — 运行 您在多进程(和线程,最好)中的后端。 IE。用 gunicorn 部署你的烧瓶,给它多个工作进程。这样,您将拥有能够执行 number_of_processes - 1
繁重计算的系统,并且仍然可以处理请求。进程限制通常高达 cpu_cores * 2
,具体取决于 cpu arch.
稍微复杂一点:
- 接受数据
- 运行不同进程中的重函数
- 收集结果,return
ProcessPoolExecutor
的最佳界面。缺点是 - 更难处理 failures/process 挂在
另一种方式是任务队列+工作线程。最常用的一个是 celery
。想法是
- 打开 WS 连接
- 将任务放入队列
- worker(在不同的进程甚至不同的物理节点)最终拿起任务,计算它,把结果放在一些数据库中
- 主进程获得 callback/result 对结果 DB
的长轮询
- 主进程通过 WS 发送结果
这更适合真正繁重且非实时的任务,但为您提供开箱即用的处理 failures/restarts/etc。
我有一个 Android 客户端应用程序,它向 Python 中的服务器发送一些数据,其中 Python 服务器应该 运行 耗时很长operation/computation 和 return 结果给客户端。
为此,我最初开始在服务器端使用 Python 的 Flask,在客户端使用 asynchronous android http library 通过 http POST 发送数据。但是,我很快注意到这不是要走的路,因为服务器上的计算需要时间,这会导致客户端出现超时错误等问题
然后,我开始在客户端使用Tornado's Websockets on the server side, and an android library for websockets。然而,第一个主要问题是,当服务器正在 运行ning 给定客户端的耗时操作时,其他潜在客户端需要等待......而且让 tornado 工作似乎有点痛苦在多线程设置中(因为它最初计划是单线程的)。另一个小问题是,如果客户端在服务器正在处理他的请求时掉线,那么当他重新连接时,客户端可能永远得不到结果。
因此,我想问一下,如果我想使用异步多线程 Python 服务器进行这样的设置,我是否有任何解决方案或建议使用什么? cpu 使用来自客户端的数据进行计算,而无需让其他潜在客户端等待轮到他们;并有可能使客户端在连接回来时能够从服务器获取结果。
首先,如果您要在后端执行 cpu-繁重的 操作,您 [很可能] 需要 运行它在单独的 进程 中。不在 thread/coro/etc 中。原因是 python 有时仅限于单线程(您可以阅读有关 GIL 的更多信息)。在多线程中执行 cpu 繁重的操作可为您的后端提供一些可用性,但会影响整体性能。
Simple/old 解决方案 — 运行 您在多进程(和线程,最好)中的后端。 IE。用 gunicorn 部署你的烧瓶,给它多个工作进程。这样,您将拥有能够执行
number_of_processes - 1
繁重计算的系统,并且仍然可以处理请求。进程限制通常高达cpu_cores * 2
,具体取决于 cpu arch.稍微复杂一点:
- 接受数据
- 运行不同进程中的重函数
- 收集结果,return
ProcessPoolExecutor
的最佳界面。缺点是 - 更难处理 failures/process 挂在另一种方式是任务队列+工作线程。最常用的一个是
celery
。想法是- 打开 WS 连接
- 将任务放入队列
- worker(在不同的进程甚至不同的物理节点)最终拿起任务,计算它,把结果放在一些数据库中
- 主进程获得 callback/result 对结果 DB 的长轮询
- 主进程通过 WS 发送结果
这更适合真正繁重且非实时的任务,但为您提供开箱即用的处理 failures/restarts/etc。