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

aar*_*vin 25 python long-polling flask

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

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

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

这是我的问题:

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

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

谢谢你的帮助!

Jon*_*ice 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的方法.

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

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

  • 啊,谢谢*这么多啊!我今晚要看看你的代码."但根据我的经验,找到好的,简单的服务器端实现示例一直很困难." 这是我的确切经历,所以我很高兴听到我并不孤单.再次感谢!! (2认同)

Jon*_*ice 10

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

这是一个示例,类似于上面的示例,但集成了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()
Run Code Online (Sandbox Code Playgroud)

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