合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
### Navigation - [index](# "General Index") - [modules](# "Python Module Index") | - [next](# "Release notes") | - [previous](# "tornado.util — General-purpose utilities") | - [Tornado 4.4.dev1 documentation](#) » # Frequently Asked Questions - [Why isn't this example with `time.sleep()` running in parallel?](#) - [My code is asynchronous, but it's not running in parallel in two browser tabs.](#) ### [Why isn't this example with `time.sleep()` running in parallel?](#) Many people's first foray into Tornado's concurrency looks something likethis: ~~~ class BadExampleHandler(RequestHandler): def get(self): for i in range(5): print(i) time.sleep(1) ~~~ Fetch this handler twice at the same time and you'll see that the secondfive-second countdown doesn't start until the first one has completelyfinished. The reason for this is that [`time.sleep`](https://docs.python.org/3.4/library/time.html#time.sleep "(in Python v3.4)") [https://docs.python.org/3.4/library/time.html#time.sleep] is a **blocking**function: it doesn't allow control to return to the [`IOLoop`](# "tornado.ioloop.IOLoop") so that otherhandlers can be run. Of course, [`time.sleep`](https://docs.python.org/3.4/library/time.html#time.sleep "(in Python v3.4)") [https://docs.python.org/3.4/library/time.html#time.sleep] is really just a placeholder in these examples,the point is to show what happens when something in a handler gets slow.No matter what the real code is doing, to achieve concurrency blockingcode must be replaced with non-blocking equivalents. This means one of three things: 1. *Find a coroutine-friendly equivalent.* For [`time.sleep`](https://docs.python.org/3.4/library/time.html#time.sleep "(in Python v3.4)") [https://docs.python.org/3.4/library/time.html#time.sleep], use[`tornado.gen.sleep`](# "tornado.gen.sleep") instead: ~~~ class CoroutineSleepHandler(RequestHandler): @gen.coroutine def get(self): for i in range(5): print(i) yield gen.sleep(1) ~~~ When this option is available, it is usually the best approach.See the [Tornado wiki](https://github.com/tornadoweb/tornado/wiki/Links) [https://github.com/tornadoweb/tornado/wiki/Links]for links to asynchronous libraries that may be useful. 1. *Find a callback-based equivalent.* Similar to the first option,callback-based libraries are available for many tasks, although theyare slightly more complicated to use than a library designed forcoroutines. These are typically used with [`tornado.gen.Task`](# "tornado.gen.Task") as anadapter: ~~~ class CoroutineTimeoutHandler(RequestHandler): @gen.coroutine def get(self): io_loop = IOLoop.current() for i in range(5): print(i) yield gen.Task(io_loop.add_timeout, io_loop.time() + 1) ~~~ Again, the[Tornado wiki](https://github.com/tornadoweb/tornado/wiki/Links) [https://github.com/tornadoweb/tornado/wiki/Links]can be useful to find suitable libraries. 1. *Run the blocking code on another thread.* When asynchronous librariesare not available, [`concurrent.futures.ThreadPoolExecutor`](https://docs.python.org/3.4/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor "(in Python v3.4)") [https://docs.python.org/3.4/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor] can be usedto run any blocking code on another thread. This is a universal solutionthat can be used for any blocking function whether an asynchronouscounterpart exists or not: ~~~ executor = concurrent.futures.ThreadPoolExecutor(8) class ThreadPoolHandler(RequestHandler): @gen.coroutine def get(self): for i in range(5): print(i) yield executor.submit(time.sleep, 1) ~~~ See the [*Asynchronous I/O*](#) chapter of the Tornadouser's guide for more on blocking and asynchronous functions. ### [My code is asynchronous, but it's not running in parallel in two browser tabs.](#) Even when a handler is asynchronous and non-blocking, it can be surprisinglytricky to verify this. Browsers will recognize that you are trying toload the same page in two different tabs and delay the second requestuntil the first has finished. To work around this and see that the serveris in fact working in parallel, do one of two things: - Add something to your urls to make them unique. Instead of`http://localhost:8888` in both tabs, load`http://localhost:8888/?x=1` in one and`http://localhost:8888/?x=2` in the other. - Use two different browsers. For example, Firefox will be able to loada url even while that same url is being loaded in a Chrome tab. © Copyright 2009-2016, The Tornado Authors. Created using [Sphinx](http://sphinx-doc.org/) 1.3.5.