转载http://xiaorui.cc/2014/11/26/tornado调用ioloop-tracebackfuture实现非堵塞的模块/
当然实现的方法,还是存在点问题的, 但是最少流程是跑通了。 我在用ab做测试的时候,会发现数据已经进入到ioloop里面,但是逻辑堵塞到我们调用的函数上。
tornado.web.asynchronous
的作用是保持长连接,也就是除非你主动调用self.finish()
方法,否则requestHandler
将不会返回。
tornado.gen.coroutine
是使用协程的方式实现类似异步的处理效果。最新版的tornado,其实不一定需要写
下一步再写一个,tornado redis brpop的非堵塞模块。
咱们先来看看,tornado的那个异步的装饰器@gen.coroutine,到底做了什么事情?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
def _make_coroutine_wrapper(func, replace_callback):
@functools.wraps(func)
def wrapper(*args, **kwargs):
runner = None
future = TracebackFuture() #创建了一个新的Future对象,这货就是Future.
if replace_callback and 'callback' in kwargs:
callback = kwargs.pop('callback')
IOLoop.current().add_future(
future, lambda future: callback(future.result())) #当future执行完就把callback加入ioloop.
try:
result = func(*args, **kwargs) #调用被装饰函数
except (Return, StopIteration) as e:
result = getattr(e, 'value', None)
except Exception:
future.set_exc_info(sys.exc_info())
return future
else:
if isinstance(result, types.GeneratorType): #如果被装饰函数被调用后产生一个Generator就用一个Runner来让future调用result.
runner = Runner(result, future)
runner.run()
return future
future.set_result(result)
return future
return wrapper
|
这个是tornado的demo,异步的逻辑需要你用yield async来生成的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine
import torasync
import time
def test(a):
time.sleep(3)
print 'coming'
return 'ok'
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
result = yield tornasync.async(test, "xiaorui.cc")
self.write("%s" % result )
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
from tornado.concurrent import TracebackFuture
from tornado.ioloop import IOLoop
def async(task, *args, **kwargs):
callback = kwargs.pop("callback", None)
if callback:
IOLoop.instance().add_future(future,
lambda future: callback(future.result()))
result = task(*args,**kwargs)
IOLoop.instance().add_callback(_on_result, result, future)
return future
def _on_result(result, future):
# if result is not ready, add callback function to next loop,
if result:
future.set_result(result)
else:
IOLoop.instance().add_callback(_on_result, result, future)
|