【问题标题】:Django - How to properly send a request to server and ask to run a matlab program?Django - 如何正确向服务器发送请求并要求运行 matlab 程序?
【发布时间】:2018-04-14 23:19:03
【问题描述】:

我在服务器上有一个 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 代码需要一段时间才能完成,并且总是使客户端超时,这是不可接受的。我的问题是如何以另一种方式解决此类问题。发布请求似乎不是一个好的解决方案。

【问题讨论】:

    标签: python django


    【解决方案1】:

    这将是一个异步操作。默认情况下,这不是 django 内置的,但是有几种方法可以使它成为可能。

    最常见的选择可能是使用 Celery。这是一个分布式任务队列,可以和 django 结合使用。它还要求您安装消息代理,例如 RabbitMQ。

    http://www.celeryproject.org/

    较新的替代方案是 django 频道,它是 django 项目的一部分,但不是 django 的默认部分(至少现在还没有)。

    https://github.com/django/channels

    有关这两个项目的更多比较,请参阅此问题。 How Django channels are different than celery?

    这两个库都相当复杂。如果您正在寻找更轻量级的替代品,请参阅以下问题:

    Simple approach to launching background task in Django

    【讨论】:

    • 我确实使用了django-channels。但是,当处理时间(matlab)增加到一个级别时,浏览器会显示超时。不知道是不是因为post请求没有得到任何响应。
    【解决方案2】:

    你可以让它异步。

    对于异步,我的意思是在发布请求中,您将生成一个标识操作的 uuid。 您将使用不同的线程/进程在发布请求中启动操作。

    要检查操作是否完成,您必须设置一个状态视图,其中给定操作 id 将返回其状态。

    仅添加一个代码 sn-p 作为概念证明。我没有测试!

    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):
        .....
        .....
    

    【讨论】:

      猜你喜欢
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 1970-01-01
      • 2016-06-22
      • 1970-01-01
      相关资源
      最近更新 更多