我正在使用Tornado开发Web套接字应用程序。 我需要处理同时连接并能够并行处理请求。
是的,默认情况下Tornado不是线程安全的,所以我必须在我的应用程序中自己完成。 文档在线程安全的websocket处理程序中没有说太多,所以我想问一些已经对它进行过实验的反馈。
更新的
这是描述问题的最小代码:
handler.py
# -*- coding: utf-8 -*-
import re, zmq, json, sys, time
import tornado.ioloop
import tornado.web
import tornado.websocket
from subprocess import Popen, PIPE, STDOUT
from tornado.options import define, options
define("port", default=9000, help="run on the given port", type=int)
clients = []
class JobProgressHandler(tornado.websocket.WebSocketHandler):
def open(self, *args):
if self not in clients:
clients.append(self)
self.stream.set_nodelay(True)
def on_message(self, script_uid):
print 'Starting verbose for : ', script_uid
self.send_progress(script_uid)
def on_close(self):
print 'Closing: ', self
if self in clients:
clients.remove(self)
def send_progress(self, script_uid):
"""
Send a fake job progress
"""
for x in xrange(10):
self.write_message(json.dumps({script_uid: (x+1)*10}))
#time.sleep(1)
print script_uid, (x+1)*10
server.py
# -*- coding: utf-8 -*-
import tornado.web
from tornado.options import options, parse_command_line
from handler import JobProgressHandler
app = tornado.web.Application([
(r'/jobprogress', JobProgressHandler),
])
if __name__ == '__main__':
parse_command_line()
app.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
test.js(在浏览器的控制台中测试)
function websock(script_name)
{
var ws = new WebSocket("ws://localhost:9000/jobprogress");
ws.onopen = function(){ws.send(script_name); console.log("Socket opened");};
ws.onmessage = function (evt){console.log(evt.data);};
ws.onclose = function(){console.log("Connection is closed ...");};
}
websock('diagnostics.eth0');
websock('diagnostics.eth1');
答案 0 :(得分:3)
在下面的代码中,您可以在IOLoop中添加一个回调,告诉它在可能的情况下运行您的方法。然后它将更新WS客户端,并为其自身添加另一个回调,以便在1秒后执行。据我所知,指定的时间可能不是确切的时间。
它本质上做的是它告诉IOLoop“继续并处理其他事件,在大约1秒内,你可以调用我的功能”。我上面提到的其他事件可能是任何事情。它可以为来自其他WS客户端的新的开放连接请求提供服务,也可以是更新其处理程序等的其他回调。
另外,我强烈建议您阅读一些有关Python异步概念和编程的内容。
请注意,下面的代码未经过测试,但它应该可以正常工作。如果您需要进行更改以使其正常工作,请与我们联系。
from functools import partial
import datetime
def send_update(self, script_uid, max=10):
self.write_message(json.dumps({script_uid: (script_uid+1)*10}))
if script_uid > max:
return
io_loop.add_timeout(datetime.timedelta(seconds=1), partial(self.send_update, script_uid + 1))
答案 1 :(得分:2)
为什么需要线程?龙卷风不是线程安全的原因是因为它是为单个线程中的事件驱动的并发而设计的;您不需要线程来支持许多同时连接。如果你将线程与龙卷风结合起来,你需要非常小心线程之间的切换,因为几乎所有龙卷风方法都只能从IOLoop线程安全地调用。