Python中的非消息队列/简单长轮询(和Flask)

问题描述 投票:25回答:2

我正在寻找一个简单的(即,不是一个需要我设置一个单独的服务器来处理消息队列)的方法来对运行计算并生成图形的小型Web界面进行长轮询。这就是我的web界面需要做的事情:

  1. 用户在Web界面中请求图形/数据
  2. 服务器运行一些计算。
  3. 当服务器正在运行计算时,一个小容器会更新(可能通过AJAX / jQuery)计算进度(类似于你在带打印的consol中所做的那样(即打印'计算密度函数......'))
  4. 计算完成和图形显示给用户。

由于计算都在服务器端完成,我不确定如何轻松设置它。显然,我想设置一个REST API来处理轮询,这在Flask中很容易。但是,我不确定如何检索实际更新。显而易见的是,虽然这个目的很复杂,但解决方案是设置消息传递队列并进行一些长轮询。但是,我不确定这是否是这种简单方法的正确方法。

这是我的问题:

  1. 有没有办法使用文件系统执行此操作?性能不是一个大问题。 AJAX / jQuery可以从文件中查找消息吗?将进度保存到某个.json文件?
  2. 酸洗怎么样? (我真的不太了解酸洗,但也许我可以腌制消息字典,它可以通过处理轮询的API读取)。
  3. 投票甚至是正确的方法吗?是否有更好或更常见的模式来处理这个问题?

我有一种感觉,我过于复杂,因为我知道这种事情在网络上很常见。我经常看到发生的事情,并且在进行某些计算时会运行一些“loading.gif”图像(例如,在Google Analytics中)。

谢谢你的帮助!

python flask long-polling
2个回答
43
投票

我使用Flask和jQuery构建了几个这样的应用程序。根据这些经验,我会说你的计划很好。

  1. 不要使用文件系统。您将遇到JavaScript安全问题/保护。在不太可能的情况下,您找到合理的解决方法,您仍然没有任何可移植或可扩展的东西。相反,使用一个小的本地Web服务框架,如Flask。
  2. 不要泡菜。使用JSON。它是Web应用程序和REST接口的语言。 jQuery和那些用于绘制图表,图形等的基于jQuery的好插件将需要JSON。它易于使用,易于阅读,对于小型应用程序,没有理由去任何其他地方。
  3. 长轮询对于您想要完成的任务很好。纯基于HTTP的应用程序有一些限制。而像Socket.IO这样的WebSockets和类似的socket-ish层就是未来。但是,根据我的经验,找到好的,简单的服务器端实现示例一直很困难。我看起来很努力。有很多示例要求您设置Node.js,REDIS和其他中间件。但为什么我们要设置两个或三个独立的中间件服务器?真是荒唐可笑。因此,对像Flask这样简单,纯粹的Python Web框架进行长时间轮询是实现IMO的方法。

代码不仅仅是一个片段,所以我没有把它包含在这里,而是将一个简化的例子放到a Mercurial repository on bitbucket中,你可以自由地复习,复制或克隆。有三个部分:

  • serve.py是一个基于Python / Flask的服务器
  • templates/index.html 98%HTML,2%模板文件基于Flask的服务器将呈现为HTML
  • static/lpoll.js是一个基于jQuery的客户端

10
投票

在对大多数浏览器进行简单,自然的Web套接字支持之前,以及在与Flask应用程序一起轻松集成之前,长轮询是一种合理的解决方法。但是在2013年中期,Web Socket支持已经走过了漫长的道路。

Here is an example,类似于上面的那个,但集成了Flask和Web Sockets。它运行在geventgevent-websocket的服务器组件之上。

请注意,此示例并非旨在成为Web Socket杰作。它保留了许多lpoll结构,使它们更容易比较。但它立即提高了Web应用程序的响应能力,服务器开销和交互性。

Python 3.7+的更新

自最初回答5年以来,WebSocket变得更容易实现。从Python 3.7开始,异步操作已经成熟为主流实用性。 Python Web应用程序是完美的用例。他们现在可以像JavaScript和Node.js一样使用异步,留下了“并发性”的一些怪癖和复杂性。特别是,请查看Quart。它保留了Flask的API以及与许多Flask扩展的兼容性,但是启用了异步。一个关键的副作用是WebSocket连接可以与HTTP连接并行地优雅地处理。例如。:

from quart import Quart, websocket

app = Quart(__name__)

@app.route('/')
async def hello():
    return 'hello'

@app.websocket('/ws')
async def ws():
    while True:
        await websocket.send('hello')

app.run()

Quart只是升级到Python 3.7的众多重要原因之一。

© www.soinside.com 2019 - 2024. All rights reserved.