Asynchronous COMET query with Tornado and Prototype

柔情痞子 提交于 2019-12-03 02:06:00

问题


I'm trying to write simple web application using Tornado and JS Prototype library. So, the client can execute long running job on server. I wish, that this job runs Asynchronously - so that others clients could view page and do some stuff there.

Here what i've got:

#!/usr/bin/env/ pytthon

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()

This is server part. It has main view (shows little greeting, current server time and url for ajax query, that executes long running job. If you press a button, a long running job executes. And server hangs :( I can't view no pages, while this job is running. Here is template page:

<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>

what am I doing wrong? How can implement long pooling, using Tornado and Prototype (or jQuery)

PS: I have looked at Chat example, but it too complicated. Can't understand how it works :(

PSS Download full example


回答1:


Tornado is single-threaded web server. Your while loop in wait_for_smith method is blocking Tornado.

You can rewrite that method like this:

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()

You need to add import time at the top to make this work.




回答2:


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

should be

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



回答3:


I've converted Tornado's chat example to run on gevent. Take a look at the live demo here and the explanation and source code here.

It uses lightweight user-level threads (greenlets) and is comparable in speed/memory use with Tornado. However, the code is straightforward, you can call sleep() and urlopen() in your handlers without blocking the whole process and you can spawn long running jobs that do the same. Under the hood the application is asynchronous, powered by an event loop written in C (libevent).

You can read the introduction here.




回答4:


I have read the book called "Building the Realtime User Experience" by Ted Roden, and it was very helpful. I have managed to create a complex realtime chat system using Tornado (python). I recommend this book to be read as well as "Foundations of Python Network Programming" by John Goerzen.



来源:https://stackoverflow.com/questions/2317501/asynchronous-comet-query-with-tornado-and-prototype

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!