Skip to content

Instantly share code, notes, and snippets.

@lwzm
Last active November 29, 2016 02:54
Show Gist options
  • Save lwzm/6789d667f5bb7f38547fab3e115f4e6b to your computer and use it in GitHub Desktop.
Save lwzm/6789d667f5bb7f38547fab3e115f4e6b to your computer and use it in GitHub Desktop.
测试 tornado 的异步, 注意异步回调函数用 tornado.stack_context.wrap 还有一个协程的版本, 简直太帅了, 利用 future, 清晰明了
#!/usr/bin/env python3
import collections
import tornado.concurrent
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.gen
import tornado.stack_context
class Handler(tornado.web.RequestHandler):
_queues = collections.defaultdict(collections.deque)
_callbacks = {}
def set_default_headers(self):
self.set_header("Content-Type", "text/plain; charset=UTF-8")
self.set_header("Cache-Control", "no-store")
@classmethod
def to(cls, token, msg):
q = cls._queues[token]
q.append(msg)
cls._flush(token)
@classmethod
def _flush(cls, token):
f = cls._callbacks.pop(token, None)
if f:
f()
@tornado.web.asynchronous
def get(self, token):
q = self._queues[token]
def f():
if q:
self.finish(q.popleft())
else:
self.set_status(204)
self.finish()
if q:
f()
else:
self._flush(token)
assert token not in self._callbacks # after _flush
self._callbacks[token] = tornado.stack_context.wrap(f)
class Handler2(tornado.web.RequestHandler):
def get(self, token):
Handler.to(token, "hi")
application = tornado.web.Application([
(r"/_/(.+)", Handler2),
(r"/(.+)", Handler),
], debug=True)
if __name__ == "__main__":
import tornado.options
tornado.options.parse_command_line()
application.listen(1111, xheaders=True)
tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env python3
import collections
import tornado.concurrent
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.gen
class Base(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header("Content-Type", "text/plain; charset=UTF-8")
self.set_header("Cache-Control", "no-store")
class Handler(Base):
_futures = collections.defaultdict(list)
@classmethod
def to(cls, token, msg):
lst = cls._futures[token]
while lst:
lst.pop().set_result(msg)
@tornado.gen.coroutine
def get(self, token):
future = tornado.concurrent.Future()
self._futures[token].append(future)
result = yield future
self.write(result)
class Handler2(Base):
def get(self, token):
Handler.to(token, "hi")
self.write(token)
application = tornado.web.Application([
(r"/_/(.+)", Handler2),
(r"/(.+)", Handler),
], static_path="static", template_path="templates", debug=True)
if __name__ == "__main__":
import tornado.options
tornado.options.parse_command_line()
application.listen(1111, xheaders=True)
tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env python3
import threading
import time
import concurrent.futures
import requests
local = threading.local()
def get(url):
try:
session = local.session
except AttributeError:
session = local.session = requests.Session()
resp = session.get(url)
assert resp.status_code < 400
return resp.text
def main():
n = 100
pool = concurrent.futures.ThreadPoolExecutor(n)
futures = [pool.submit(get, "http://localhost:1111/{}".format(1))
for i in range(n)]
time.sleep(0.3)
get("http://localhost:1111/_/1")
print(futures)
for future in concurrent.futures.as_completed(futures):
print(future.result())
pool.shutdown()
def main2():
n = 100
cli = tornado.httpclient.AsyncHTTPClient(max_clients=50)
@tornado.gen.coroutine
def f1():
x = yield cli.fetch("http://localhost:1111/1")
print(x.body.decode())
io_loop = tornado.ioloop.IOLoop.current()
for i in range(n):
io_loop.spawn_callback(f1)
@tornado.gen.coroutine
def f2():
for _ in range(n // cli.max_clients + 1):
yield tornado.gen.sleep(0.3)
get("http://localhost:1111/_/1")
yield tornado.gen.sleep(0.1)
io_loop.stop()
io_loop.spawn_callback(f2)
io_loop.start()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment