为什么龙卷风不并发?
Why tornado doesn't go concurrently?
以下是我的测试代码。我正在使用 Python2.7,安装 futures
使用:
pip install futures
以下是我的演示代码:
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine, Task
from tornado.concurrent import Future
import time
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
print "in"
res = yield Task(self._work)
self.write(res)
def _work(self, callback):
time.sleep(10)
callback("hello world!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
这段代码应该是并发的,不是吗?然而,事实并非如此。
我用 Firefox 和 IE 测试过。我想我犯了一些错误。如果你能指出我的错误,那就太好了。
一次只能请求一个(http://localhost:8888/
:
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine, Return, Task
from tornado.process import Subprocess
from tornado.concurrent import Future
from threading import Thread
import time
@coroutine
def async_sleep(timeout):
""" Sleep without blocking the IOLoop. """
yield Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + timeout)
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
print "in"
res = yield self._work()
self.write(res)
@coroutine
def _work(self):
yield async_sleep(5)
raise Return("hello world!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
ioloop=tornado.ioloop.IOLoop.instance()
Thread(target=ioloop.start).start()
由于您在评论中指出要通过龙卷风 运行 子流程,这里有一个示例说明如何做到这一点。我还修复了您在调用 _work
时创建 Task
的逻辑错误,该错误不会按您预期的方式工作:
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine, Return
from tornado.process import Subprocess
from tornado.concurrent import Future
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
print "in"
res = yield self._work()
self.write(res)
@coroutine
def _work(self):
p = Subprocess(['sleep', '10'])
f = Future()
p.set_exit_callback(f.set_result)
yield f
raise Return("hello world!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
大家可以看到,我把_work
做了一个协程,然后用tornado's built-in Subprocess
class执行了一个命令。我创建了一个 Future
对象,并指示 Subprocess
在它完成时调用 Future.set_result(return_code_of_subprocess)
。然后我在 Future
实例上调用了 yield
。这使得代码一直等到子进程完成,而不会阻塞 I/O 循环。
你代码中的time.sleep
是一个阻塞方法。
你需要 tornado.gen.sleep
(一种非阻塞方法,tornado 4.1 中的新方法)来代替。
以下是我的测试代码。我正在使用 Python2.7,安装 futures
使用:
pip install futures
以下是我的演示代码:
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine, Task
from tornado.concurrent import Future
import time
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
print "in"
res = yield Task(self._work)
self.write(res)
def _work(self, callback):
time.sleep(10)
callback("hello world!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
这段代码应该是并发的,不是吗?然而,事实并非如此。
我用 Firefox 和 IE 测试过。我想我犯了一些错误。如果你能指出我的错误,那就太好了。
一次只能请求一个(http://localhost:8888/
:
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine, Return, Task
from tornado.process import Subprocess
from tornado.concurrent import Future
from threading import Thread
import time
@coroutine
def async_sleep(timeout):
""" Sleep without blocking the IOLoop. """
yield Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + timeout)
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
print "in"
res = yield self._work()
self.write(res)
@coroutine
def _work(self):
yield async_sleep(5)
raise Return("hello world!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
ioloop=tornado.ioloop.IOLoop.instance()
Thread(target=ioloop.start).start()
由于您在评论中指出要通过龙卷风 运行 子流程,这里有一个示例说明如何做到这一点。我还修复了您在调用 _work
时创建 Task
的逻辑错误,该错误不会按您预期的方式工作:
import tornado.ioloop
import tornado.web
from tornado.gen import coroutine, Return
from tornado.process import Subprocess
from tornado.concurrent import Future
class MainHandler(tornado.web.RequestHandler):
@coroutine
def get(self):
print "in"
res = yield self._work()
self.write(res)
@coroutine
def _work(self):
p = Subprocess(['sleep', '10'])
f = Future()
p.set_exit_callback(f.set_result)
yield f
raise Return("hello world!")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
大家可以看到,我把_work
做了一个协程,然后用tornado's built-in Subprocess
class执行了一个命令。我创建了一个 Future
对象,并指示 Subprocess
在它完成时调用 Future.set_result(return_code_of_subprocess)
。然后我在 Future
实例上调用了 yield
。这使得代码一直等到子进程完成,而不会阻塞 I/O 循环。
你代码中的time.sleep
是一个阻塞方法。
你需要 tornado.gen.sleep
(一种非阻塞方法,tornado 4.1 中的新方法)来代替。