Python 如何显示';处理';或';进行中';是否在金字塔运行进程时查看?

Python 如何显示';处理';或';进行中';是否在金字塔运行进程时查看?,python,pyramid,Python,Pyramid,我已经启动并运行了一个简单的pyramid应用程序,大多数视图都是围绕sqlite数据库的一个相当薄的包装,其中包含用于编辑/添加一些信息的表单 每月有几次,需要将新的数据块添加到此系统(通过csv导入)。数据保存在SQL表中(整个过程直到提交大约需要4秒) 每次上载新的数据块时,都会触发对数据库中其他表的重新计算。重新计算过程需要相当长的时间(一个月的数据大约需要21-50秒) 目前,我只是让浏览器/客户端坐在那里等待过程完成,但我确实预见到,随着系统使用率的提高,计算过程将花费越来越多的时间

我已经启动并运行了一个简单的pyramid应用程序,大多数视图都是围绕sqlite数据库的一个相当薄的包装,其中包含用于编辑/添加一些信息的表单

每月有几次,需要将新的数据块添加到此系统(通过csv导入)。数据保存在SQL表中(整个过程直到提交大约需要4秒)

每次上载新的数据块时,都会触发对数据库中其他表的重新计算。重新计算过程需要相当长的时间(一个月的数据大约需要21-50秒)

目前,我只是让浏览器/客户端坐在那里等待过程完成,但我确实预见到,随着系统使用率的提高,计算过程将花费越来越多的时间。从UI的角度来看,这显然看起来像一个挂起的进程

我可以如何向用户指出:-

  • 长时间的等待是正常的/预期的

  • 他们还需要等待多久(进度条等)

  • 注意:我并不是在这里询问长轮询或WebSocket,因为这不是一个真正的交互式应用程序,并且基于我的基本知识,WebSocket/async对于我来说是一种过分的技巧


    我想接下来的问题是,在我的视图函数中运行进程是否做了错误的事情?在网上的示例/教程中几乎看不到这一点。在这种情况下,我应该使用芹菜或类似的东西吗?

    你是对的,在视图函数中进行长时间的计算通常是不受欢迎的-我的意思是,如果这是一个典型的网站,随机访问者能够挂起一分钟的Web服务器线程,那么这就是造成DoS漏洞的原因。但在某些情况下(内部网站,很少有用户,只有管理员可以访问“上传csv”表单),您可能会侥幸逃脱。事实上,我曾经有运行数小时的维护脚本:)

    这里的诀窍是避免浏览器超时——此时,您的客户机将数据发送到服务器,只是坐在那里等待任何回复,而不知道他们的请求是否正在被处理。通常,在大约60秒时,浏览器(或代理,或前端Web服务器)可能会变得不耐烦并关闭连接。然后,服务器进程将在尝试将任何内容写入已关闭的连接时出错,并导致崩溃/引发错误

    为了防止这种情况发生,服务器需要定期向连接写入内容,以便客户端看到服务器处于活动状态,并且不会关闭连接

    “普通”金字塔模板是缓冲的,即在生成整个模板之前,输出不会发送到客户端。因此,您需要直接使用
    response.app\u iter
    /
    response.body\u文件
    ,并定期在那里输出一些数据

    例如,您可以复制Pyramid Cookbook中的示例,并用以下代码替换
    new\u view
    函数(其本身已从中借用):

    @view\u config(路由\u name='new',请求\u方法='GET',呈现器='new.mako')
    def新视图(请求):
    返回{}
    @查看配置(路由名称='new',请求方法='POST')
    def iter_测试(请求):
    导入时间
    if request.POST.get('name'):
    request.db.execute(
    '插入到任务(名称,关闭)值(?,)',
    [request.POST['name'],0])
    request.db.commit()
    def测试仪():
    i=0
    尽管如此:
    i+=1
    如果i==5:
    yield str(“完成!查看结果”

    ) 提出停止迭代 屈服强度('正在工作的%s..

    '%i) 打印时间 时间。睡眠(1) 返回响应(app_iter=test_iter())

    (当然,这个解决方案在用户界面方面不是太花哨,但你说过你不想弄乱WebSocket和芹菜)

    那么长时间运行的过程是由浏览器操作触发的吗?也就是说,用户正在上传得到处理的CSV,然后视图正在那里进行处理?对于短时间运行的浏览器进程,我通过jQuery或javascript使用了加载指示器,基本上是在进程运行时弹出一个模式动画微调器或其他东西,然后在它完成隐藏微调器时弹出


    但是如果你进入越来越长的进程,我认为你应该真正考虑一些后台处理,它将从UI中卸载。它不必是基于消息的worker,但即使是最终用户上传文件,并在数据库中设置“待处理”条目。然后,您可以在后台安排一个定期轮询状态表并运行它找到的任何内容。您可以将视图中的文件处理移动到单独的方法,并且可以从命令行脚本调用该方法。然后,当处理完成时,它可以更新状态表,指示它已完成,并且可以在某个地方将反馈返回给用户,而不会一直阻塞用户界面

    我对这个问题很感兴趣,并尝试了你的答案。一次渲染所有输出(全部5行)。对吗?我以为它会一次显示一行“正在工作”的输出,直到完成为止。@fatfantasma:这可能是由Web服务器(女服务员和/或前端Web服务器,如Nginx)引起的同时缓冲输出-请看这个答案:我用一个旧的Pyramid设置进行了测试,它使用PasteDeploy,每秒打印一行。@fatfantasma:作为一个有趣的实验,您可以尝试在每行之后写入大量空格,以迫使Web服务器刷新缓冲区。浏览器输出看起来是一样的,因为空格将被折叠。不确定我是否会在生产中尝试此方法,但类似的方法会奏效:yield str(“正在工作的%s…”。

    %s”“(I,*20000))I tri
    @view_config(route_name='new', request_method='GET', renderer='new.mako')
    def new_view(request):
        return {}
    
    
    @view_config(route_name='new', request_method='POST')
    def iter_test(request):
        import time
    
        if request.POST.get('name'):
            request.db.execute(
                'insert into tasks (name, closed) values (?, ?)',
                [request.POST['name'], 0])
            request.db.commit()
    
    
        def test_iter():
            i = 0
            while True:
                i += 1
                if i == 5:
                    yield str('<p>Done! <a href="/">Click here</a> to see the results</p>')
                    raise StopIteration
                yield str('<p>working %s...</p>' % i)
                print time.time()
                time.sleep(1)
    
        return Response(app_iter=test_iter())