使用Tornado和Prototype进行异步COMET查询

9

我正在尝试使用Tornado和JS Prototype库编写简单的Web应用程序。这样,客户端可以在服务器上执行长时间运行的作业。我希望这个作业能够异步运行,以便其他客户端可以查看页面并在页面上进行一些操作。

以下是我已经得到的内容:

#!/usr/bin/env/ python

import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options

import os
import string
from time import sleep
from datetime import datetime

define("port", default=8888, help="run on the given port", type=int)

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("templates/index.html", title="::Log watcher::", c_time=datetime.now())

class LongHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        self.wait_for_smth(callback=self.async_callback(self.on_finish))
        print("Exiting from async.")
        return

    def wait_for_smth(self, callback):
        t=0
        while (t < 10):
            print "Sleeping 2 second, t={0}".format(t)
            sleep(2)
            t += 1
        callback()

    def on_finish(self):
        print ("inside finish")
        self.write("Long running job complete")
        self.finish()



def main():
    tornado.options.parse_command_line()

    settings = {
        "static_path": os.path.join(os.path.dirname(__file__), "static"),
        }

    application = tornado.web.Application([
        (r"/", MainHandler),
        (r"/longPolling", LongHandler)
        ], **settings
    )
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()

这是服务器部分。它有主视图(展示简短的问候语、当前服务器时间和用于执行长时间运行作业的ajax查询的url)。如果你按下按钮,就会执行一个长时间运行的作业。而服务端会挂起 :( 在此作业正在运行时,我无法查看任何页面。 以下是模板页面:

<html>
<head>
    <title>{{ title }}</title>

    <script type="text/javascript" language="JavaScript" src="{{ static_url("js/prototype.js")}}"></script>


    <script type='text/javascript' language='JavaScript'>
        offset=0
        last_read=0

        function test(){
            new Ajax.Request("http://172.22.22.22:8888/longPolling",
            {
                method:"get",
                asynchronous:true,
                onSuccess: function (transport){
                    alert(transport.responseText);
                }
            })
        }

        
    </script>
</head>
<body>
    Current time is {{c_time}}
    <br>
    <input type="button" value="Test" onclick="test();"/>
</body>
</html>

我做错了什么?我如何使用Tornado和Prototype(或jQuery)来实现长轮询?
PS:我已经查看了聊天示例,但它太复杂了。无法理解它是如何工作的:(
PSS 下载完整的示例
4个回答

15
龙卷风是单线程的Web服务器。在“wait_for_smith”方法中的while循环会阻塞Tornado。
您可以像这样重写该方法:
def wait_for_smth(self, callback, t=10):
    if t:
        print "Sleeping 2 second, t=%s" % t
        tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 2, lambda: self.wait_for_smth(callback, t-1))
    else:
        callback()

您需要在顶部添加import time以使此代码可用。


我已经尝试了该方法,并确认它不再挂起,但现在程序显示一个警告框,其中responseText未定义,并出现405错误。 - brainysmurf
1
说得太快了,问题出在我这里...我指定了两个不同的地址。这肯定有效。 - brainysmurf
但这是长轮询吗?在我看来,它似乎只是轮询。不过话说回来,我自己也是Tornado/Comet的新手。 - Lorenzo

1
function test(){
            new Ajax.Request("http://172.22.22.22:8888/longPolling",
            {
                method:"get",
                asynchronous:true,
                onSuccess: function (transport){
                    alert(transport.responseText);
                }
            })
        }

应该是

function test(){
            new Ajax.Request("/longPolling",
            {
                method:"get",
                asynchronous:true,
                onSuccess: function (transport){
                    alert(transport.responseText);
                }
            })
        }

如果使用非默认端口,则应传递整个路径。 - securecurve

0

我已经将Tornado的聊天示例转换为可以在gevent上运行。请查看此处的实时演示此处的解释和源代码

它使用轻量级用户级线程(greenlets),速度和内存使用与Tornado相当。但是,代码很简单,您可以在处理程序中调用sleep()和urlopen()而不会阻塞整个进程,并且您可以生成执行相同操作的长时间运行作业。在幕后,应用程序是异步的,由C编写的事件循环(libevent)提供支持。

您可以在此处阅读介绍


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接