我在服务器上有一个django web项目。我希望它运行一个 matlab 代码来生成一些文本文件(稍后会用到)。这是我的代码:
if(request.method == "POST"):
run_octave(Dataset,is_multiclass,require_mapper,mapper,require_aspect_ratio,aspect_ratio)
return redirect('meta2db.views.meta2db')
def run_octave(dataset,is_multiclass,require_mapper,mapper,require_aspect_ratio,aspect_ratio):
origWD = os.getcwd()
args = ["octave", "dbEval.m",dataset,is_multiclass,require_mapper,
mapper,require_aspect_ratio,aspect_ratio]
os.chdir(os.path.join(os.path.abspath(sys.path[0]), "../scripts/"))
#subprocess call here
process = subprocess.Popen(args, stdout=subprocess.PIPE)
for line in process.stdout:
time.sleep(0.5)
Group("eval_status").send({"text": line.decode('utf-8')},immediately=True)
if process.poll() is None:
process.kill()
else:
print(process.communicate())
os.chdir(origWD)
我使用一个后请求来运行带有子进程调用的八度代码。但是,matlab 代码需要一段时间才能完成,并且总是使客户端超时,这是不可接受的。我的问题是如何以另一种方式解决这类问题。发布请求似乎不是一个好的解决方案。
这将是一个异步操作。默认情况下,这并没有内置在 django 中,但有几种方法可以实现它。
最常见的选择可能是使用芹菜。这是一个可以与 django 结合使用的分布式任务队列。它还要求您安装消息代理,例如 RabbitMQ。
http://www.celeryproject.org/
一个较新的替代方案是 django channels,它是 django 项目的一部分,但不是 django 的默认部分(至少现在还不是)。
https://github.com/django/channels
有关两个项目的更多比较,请参阅此问题。Django 频道与芹菜有何不同?
这两个库都非常复杂。如果您正在寻找更轻量级的替代品,请参阅此问题:
在 Django 中启动后台任务的简单方法
让它异步。
对于异步,我的意思是在 post 请求中您将生成一个标识操作的 uuid。您将使用不同的线程/进程在 post 请求中启动操作。
要检查操作是否已完成,您必须设置一个状态视图,给定操作 ID 将返回其状态。
仅添加代码片段作为概念证明。我没有测试它!
from concurrent.futures import ThreadPoolExecutor
import uuid
class Operation(object):
operations = {}
def __init__(self, *task):
self.id = str(uuid.uuid4())
self.task = task
self.done = False
self._thread = None
self._executor = ThreadPoolExecutor()
self.__class__.operations[self.id] = self
def run(self):
self._thread = self.executor.submit(*self.task)
self._thread.add_done_callback(self._callback)
return self.id
def _callback(self):
self.done = True
@classmethod
def is_operation_done(cls, id):
try:
return cls.operations[id].done
except IndexError:
raise Exception("Operation not found") # FIXME Custom exception here!!
if(request.method == "POST"):
operatiorn = Operation(run_octave,
Dataset,
is_multiclass,
require_mapper,
mapper,
require_aspect_ratio,
aspect_ratio)
id = operatiorn.run()
return id # jsonize it if you wanna pass it to the frontend
def is_operatiorn_done(request, operation_id):
# This is implementing a polling but would be bettere to have a socket!
return Operation.is_operation_done(operation_id)
def run_octave(dataset,is_multiclass,require_mapper,mapper,require_aspect_ratio,aspect_ratio):
.....
.....