Django - 如何正确地向服务器发送请求并请求运行 matlab 程序



我在服务器上有一个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):
    .....
    .....

最新更新