我最近使用Django
为我的“科学计算引擎”编程我的网络界面。
我将“计算引擎”包装为python模块并在Django Framework中调用它。
“引擎”的compute()
功能需要几分钟才能运行(我使用ajax
来触发它),同时,我让前端额外增加{{1}每隔0.5秒调用一次,将CPU和内存状态更新到前端。但我发现服务器在ajax
完成之前没有响应额外的ajax
来电。
搜索后,我想我可能会使用compute()
或asynchronous
所以我在multithreading
中创建了如下所示的功能。
views.py
但是系统仍然没有响应我的额外def submit(request):
#some prepare
........
# call the engine
t = Thread(target = compute)
t.start()
return HttpResponse("started")
调用,直到ajax
完成(“引擎”仅使用了大约20%的CPU,因此还有足够的计算能力)。
我是后端编程的新手,我不确定compute()
或后端服务器如何在内部处理请求。
非常感谢,如果有人能给我一些关于如何处理这种情况的提示。
答案 0 :(得分:1)
从这样的视图中启动线程永远不是一个好主意。
解决此问题的最常见方法是将工作委托给单独的工作人员/流程。除了django之外,你还有另一个寻找工作的python进程。
您可以保持简单,并使Django视图存储有关需要以某种格式在磁盘或数据库中完成的工作的信息(这将是工作队列)。然后,工作进程将在循环中运行,每N秒检查一次可用的工作。增加工作人员/进程数量以增加更多计算能力(当然受硬件限制)
创建工作请求的http请求可以返回用户可以查询的job_id
以获取作业的状态。工作正在等待/正在进行/已完成?那么也许用户也可以获取作业的结果甚至是元数据,例如持续时间和日志?
还有一些框架可以解决像Celery和django-channels这样的问题。芹菜可能更容易入手,但对于你想要做的事情可能有点过头了。
使用这样的工作人员的优势在于,您可以在前面拥有一个非常轻量级的REST api,并且随着需求的增加,您可以扩展工作人员的数量,可能跨多个服务器。
答案 1 :(得分:1)
我终于通过使用python subprocess
我将“计算”代码放在一个单独的文件中,并使用Popen
来调用它。
from subprocess import Popen
def submit(request):
#some prepare
........
# call the engine
p = Popen(["python", "compute.py", <arguments>])
return HttpResponse("started")
然而,正如所建议的,subprocess
不是一个非常好的安全做法。此解决方案很容易实现,但我会尝试使用worker mode
或Celery
将后端转换为django-channels
,作为@Grimmy建议。