]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Add make_current keyword argument to IOLoop constructor.
authorBen Darnell <ben@bendarnell.com>
Sun, 29 Mar 2015 20:22:26 +0000 (16:22 -0400)
committerBen Darnell <ben@bendarnell.com>
Sun, 29 Mar 2015 20:31:06 +0000 (16:31 -0400)
This allows applications to create an IOLoop to be started in another
thread without making it current in the originating thread.

Update docs to use IOLoop.current() in place of IOLoop.instance() when
starting the loop.

Closes #1390.

20 files changed:
demos/benchmark/chunk_benchmark.py
demos/blog/blog.py
demos/chat/chatdemo.py
demos/facebook/facebook.py
demos/helloworld/helloworld.py
demos/s3server/s3server.py
demos/twitter/twitterdemo.py
demos/websocket/chatdemo.py
docs/asyncio.rst
docs/index.rst
docs/twisted.rst
tornado/httpclient.py
tornado/httpserver.py
tornado/ioloop.py
tornado/iostream.py
tornado/platform/twisted.py
tornado/tcpserver.py
tornado/test/process_test.py
tornado/web.py
tornado/wsgi.py

index 1502838abcc09c4a6e2526f3b3367893ab6dcbbe..ba2e0648a1a62a7659a496292d81077cf286fbc6 100755 (executable)
@@ -13,6 +13,7 @@ define('port', default=8888)
 define('num_chunks', default=1000)
 define('chunk_size', default=2048)
 
+
 class ChunkHandler(RequestHandler):
     def get(self):
         for i in xrange(options.num_chunks):
@@ -20,28 +21,30 @@ class ChunkHandler(RequestHandler):
             self.flush()
         self.finish()
 
+
 def main():
     parse_command_line()
     app = Application([('/', ChunkHandler)])
     app.listen(options.port, address='127.0.0.1')
+
     def callback(response):
         response.rethrow()
         assert len(response.body) == (options.num_chunks * options.chunk_size)
         logging.warning("fetch completed in %s seconds", response.request_time)
-        IOLoop.instance().stop()
+        IOLoop.current().stop()
 
     logging.warning("Starting fetch with curl client")
     curl_client = CurlAsyncHTTPClient()
     curl_client.fetch('http://localhost:%d/' % options.port,
                       callback=callback)
-    IOLoop.instance().start()
+    IOLoop.current().start()
 
     logging.warning("Starting fetch with simple client")
     simple_client = SimpleAsyncHTTPClient()
     simple_client.fetch('http://localhost:%d/' % options.port,
                         callback=callback)
-    IOLoop.instance().start()
-    
+    IOLoop.current().start()
+
 
 if __name__ == '__main__':
     main()
index 2707875ccb51cd8fe36ac9c84ec7631ddbbe0799..fde279e462aafcd7a446ee69080d535e06512127 100755 (executable)
@@ -231,7 +231,7 @@ def main():
     tornado.options.parse_command_line()
     http_server = tornado.httpserver.HTTPServer(Application())
     http_server.listen(options.port)
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.current().start()
 
 
 if __name__ == "__main__":
index bd4d7b085d8c667b097f2c48a7d8b8f5b156f6f3..b4978bbd9cdbf16992577da7a70c2e4854535761 100755 (executable)
@@ -125,7 +125,7 @@ def main():
         debug=options.debug,
         )
     app.listen(options.port)
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.current().start()
 
 
 if __name__ == "__main__":
index 5390a82f1ae69f59e265bf4ab13cc0e0dead9fba..ace0705fc79f0ba48105a5c7792ffee412c56b87 100755 (executable)
@@ -116,7 +116,7 @@ def main():
         return
     http_server = tornado.httpserver.HTTPServer(Application())
     http_server.listen(options.port)
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.current().start()
 
 
 if __name__ == "__main__":
index 0f1ed61ff5e07c6dd296b9c707f56015d00aedb2..06eac9290f968b6e70163a72e50faebe22da1aeb 100755 (executable)
@@ -36,7 +36,7 @@ def main():
     ])
     http_server = tornado.httpserver.HTTPServer(application)
     http_server.listen(options.port)
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.current().start()
 
 
 if __name__ == "__main__":
index 5a4805694e2426a97867f370b07461beff808b7c..ff289f025179e36ba478c9d4fc2ab3a66e80e107 100644 (file)
@@ -48,7 +48,7 @@ def start(port, root_directory="/tmp/s3", bucket_depth=0):
     application = S3Application(root_directory, bucket_depth)
     http_server = httpserver.HTTPServer(application)
     http_server.listen(port)
-    ioloop.IOLoop.instance().start()
+    ioloop.IOLoop.current().start()
 
 
 class S3Application(web.Application):
index bf14c7967c32182d0538939cd37d4f732b38f50e..73aa6ba3f96186841c758f2fdfcc0c7f948e942d 100644 (file)
@@ -87,7 +87,7 @@ def main():
     app.listen(options.port)
 
     logging.info('Listening on http://localhost:%d' % options.port)
-    IOLoop.instance().start()
+    IOLoop.current().start()
 
 if __name__ == '__main__':
     main()
index ad5b2c2e1a288296afb39efeafad6c01e5bf4f87..aac24d94e4f085a8d5293922a3ab3a06e0318a1a 100755 (executable)
@@ -99,7 +99,7 @@ def main():
     tornado.options.parse_command_line()
     app = Application()
     app.listen(options.port)
-    tornado.ioloop.IOLoop.instance().start()
+    tornado.ioloop.IOLoop.current().start()
 
 
 if __name__ == "__main__":
index b9e7459cbf1a3f56c3ac870c2514ff18408ffb03..a680350340e75f7d9f4fa3050ff47100aa32abf5 100644 (file)
@@ -41,7 +41,7 @@ loops.
 
         from tornado.ioloop import IOLoop
         IOLoop.configure('tornado.platform.asyncio.AsyncIOLoop')
-        IOLoop.instance().start()
+        IOLoop.current().start()
 
     Each ``AsyncIOLoop`` creates a new ``asyncio.EventLoop``; this object
     can be accessed with the ``asyncio_loop`` attribute.
index 92dc18230369b0a7cdf09a64c495d196b8a146f2..aae707710b64cc202fed2b7a4add575179798967 100644 (file)
@@ -46,7 +46,7 @@ Here is a simple "Hello, world" example web app for Tornado::
 
     if __name__ == "__main__":
         application.listen(8888)
-        tornado.ioloop.IOLoop.instance().start()
+        tornado.ioloop.IOLoop.current().start()
 
 This example does not use any of Tornado's asynchronous features; for
 that see this `simple chat room
index 7709e769b56ce323bedf13602813cbfc94a8a6e1..f60d08e5de042a831c20418fb0a966b86f872038 100644 (file)
@@ -22,7 +22,7 @@ Twisted on Tornado
         tornado.platform.twisted.install()
         from twisted.internet import reactor
 
-    When the app is ready to start, call ``IOLoop.instance().start()``
+    When the app is ready to start, call ``IOLoop.current().start()``
     instead of ``reactor.run()``.
 
     It is also possible to create a non-global reactor by calling
index c16563f633bf745444e000072eecdc41f87de303..c2e6862361691251659b185f097ae389a1baa654 100644 (file)
@@ -72,7 +72,7 @@ class HTTPClient(object):
         http_client.close()
     """
     def __init__(self, async_client_class=None, **kwargs):
-        self._io_loop = IOLoop()
+        self._io_loop = IOLoop(make_current=False)
         if async_client_class is None:
             async_client_class = AsyncHTTPClient
         self._async_client = async_client_class(self._io_loop, **kwargs)
index 226f966a32beea099ea4e2a78b7ce58d1bbe712b..6062b793668009e2c9f1ff35e39658e51beb5388 100644 (file)
@@ -79,7 +79,7 @@ class HTTPServer(TCPServer, Configurable,
 
             server = HTTPServer(app)
             server.listen(8888)
-            IOLoop.instance().start()
+            IOLoop.current().start()
 
        In many cases, `tornado.web.Application.listen` can be used to avoid
        the need to explicitly create the `HTTPServer`.
@@ -90,7 +90,7 @@ class HTTPServer(TCPServer, Configurable,
             server = HTTPServer(app)
             server.bind(8888)
             server.start(0)  # Forks multiple sub-processes
-            IOLoop.instance().start()
+            IOLoop.current().start()
 
        When using this interface, an `.IOLoop` must *not* be passed
        to the `HTTPServer` constructor.  `~.TCPServer.start` will always start
@@ -102,7 +102,7 @@ class HTTPServer(TCPServer, Configurable,
             tornado.process.fork_processes(0)
             server = HTTPServer(app)
             server.add_sockets(sockets)
-            IOLoop.instance().start()
+            IOLoop.current().start()
 
        The `~.TCPServer.add_sockets` interface is more complicated,
        but it can be used with `tornado.process.fork_processes` to
index f18d6985b2b9638fc4101037410a746e9d6c7f10..4a37a61cb674ba074f1a378be703e5d5c761149d 100644 (file)
@@ -104,7 +104,7 @@ class IOLoop(Configurable):
             sock.bind(("", port))
             sock.listen(128)
 
-            io_loop = tornado.ioloop.IOLoop.instance()
+            io_loop = tornado.ioloop.IOLoop.current()
             callback = functools.partial(connection_ready, sock)
             io_loop.add_handler(sock.fileno(), callback, io_loop.READ)
             io_loop.start()
@@ -112,6 +112,17 @@ class IOLoop(Configurable):
     .. testoutput::
        :hide:
 
+    By default, a newly-constructed `IOLoop` becomes the thread's current
+    `IOLoop`, unless there already is a current `IOLoop`. This behavior
+    can be controlled with the ``make_current`` argument to the `IOLoop`
+    constructor: if ``make_current=True``, the new `IOLoop` will always
+    try to become current and it raises an error if there is already a
+    current instance. If ``make_current=False``, the new `IOLoop` will
+    not try to become current.
+
+    .. versionchanged:: 4.2
+       Added the ``make_current`` keyword argument to the `IOLoop`
+       constructor.
     """
     # Constants from the epoll module
     _EPOLLIN = 0x001
@@ -140,7 +151,8 @@ class IOLoop(Configurable):
 
         Most applications have a single, global `IOLoop` running on the
         main thread.  Use this method to get this instance from
-        another thread.  To get the current thread's `IOLoop`, use `current()`.
+        another thread.  In most other cases, it is better to use `current()`
+        to get the current thread's `IOLoop`.
         """
         if not hasattr(IOLoop, "_instance"):
             with IOLoop._instance_lock:
@@ -232,8 +244,13 @@ class IOLoop(Configurable):
         from tornado.platform.select import SelectIOLoop
         return SelectIOLoop
 
-    def initialize(self):
-        if IOLoop.current(instance=False) is None:
+    def initialize(self, make_current=None):
+        if make_current is None:
+            if IOLoop.current(instance=False) is None:
+                self.make_current()
+        elif make_current:
+            if IOLoop.current(instance=False) is None:
+                raise RuntimeError("current IOLoop already exists")
             self.make_current()
 
     def close(self, all_fds=False):
@@ -400,7 +417,7 @@ class IOLoop(Configurable):
                 # do stuff...
 
             if __name__ == '__main__':
-                IOLoop.instance().run_sync(main)
+                IOLoop.current().run_sync(main)
         """
         future_cell = [None]
 
@@ -643,8 +660,8 @@ class PollIOLoop(IOLoop):
     (Linux), `tornado.platform.kqueue.KQueueIOLoop` (BSD and Mac), or
     `tornado.platform.select.SelectIOLoop` (all platforms).
     """
-    def initialize(self, impl, time_func=None):
-        super(PollIOLoop, self).initialize()
+    def initialize(self, impl, time_func=None, **kwargs):
+        super(PollIOLoop, self).initialize(**kwargs)
         self._impl = impl
         if hasattr(self._impl, 'fileno'):
             set_close_exec(self._impl.fileno())
index a0f1eee4177a62f9819a4d420a64ceb969bc34d3..3a175a679671ad4feb545e7471da2e4622e77a34 100644 (file)
@@ -971,13 +971,13 @@ class IOStream(BaseIOStream):
         def on_body(data):
             print(data)
             stream.close()
-            tornado.ioloop.IOLoop.instance().stop()
+            tornado.ioloop.IOLoop.current().stop()
 
         if __name__ == '__main__':
             s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
             stream = tornado.iostream.IOStream(s)
             stream.connect(("friendfeed.com", 80), send_request)
-            tornado.ioloop.IOLoop.instance().start()
+            tornado.ioloop.IOLoop.current().start()
 
     .. testoutput::
        :hide:
index 3d7eba42273a8c65c812bce5d15b52d508b11758..86380ba1306b6ed25eccabb563ebc6b784cb6820 100644 (file)
@@ -35,7 +35,7 @@ of the application::
     tornado.platform.twisted.install()
     from twisted.internet import reactor
 
-When the app is ready to start, call `IOLoop.instance().start()`
+When the app is ready to start, call `IOLoop.current().start()`
 instead of `reactor.run()`.
 
 It is also possible to create a non-global reactor by calling
index da5ba7bbf1efae364880e20c0ccf172c0963cb11..c9d148a80e90d8424da38360dbee0455948411f2 100644 (file)
@@ -57,14 +57,14 @@ class TCPServer(object):
 
             server = TCPServer()
             server.listen(8888)
-            IOLoop.instance().start()
+            IOLoop.current().start()
 
     2. `bind`/`start`: simple multi-process::
 
             server = TCPServer()
             server.bind(8888)
             server.start(0)  # Forks multiple sub-processes
-            IOLoop.instance().start()
+            IOLoop.current().start()
 
        When using this interface, an `.IOLoop` must *not* be passed
        to the `TCPServer` constructor.  `start` will always start
@@ -76,7 +76,7 @@ class TCPServer(object):
             tornado.process.fork_processes(0)
             server = TCPServer()
             server.add_sockets(sockets)
-            IOLoop.instance().start()
+            IOLoop.current().start()
 
        The `add_sockets` interface is more complicated, but it can be
        used with `tornado.process.fork_processes` to give you more
index 6abfabd284489b0aca3c8330f76b76c0a98a32a6..72474167ceb2727a9d51f15b3756cb6f34ce8f69 100644 (file)
@@ -85,7 +85,7 @@ class ProcessTest(unittest.TestCase):
                     self.assertEqual(id, task_id())
                     server = HTTPServer(self.get_app())
                     server.add_sockets([sock])
-                    IOLoop.instance().start()
+                    IOLoop.current().start()
                 elif id == 2:
                     self.assertEqual(id, task_id())
                     sock.close()
index 6b76e6742f5c8ae1640a1898a3b697d863aa3138..93de85c3201da0dd231280f9a95b35224ada11dd 100644 (file)
@@ -35,7 +35,7 @@ Here is a simple "Hello, world" example app:
             (r"/", MainHandler),
         ])
         application.listen(8888)
-        tornado.ioloop.IOLoop.instance().start()
+        tornado.ioloop.IOLoop.current().start()
 
 .. testoutput::
    :hide:
@@ -1664,7 +1664,7 @@ class Application(httputil.HTTPServerConnectionDelegate):
         ])
         http_server = httpserver.HTTPServer(application)
         http_server.listen(8080)
-        ioloop.IOLoop.instance().start()
+        ioloop.IOLoop.current().start()
 
     The constructor for this class takes in a list of `URLSpec` objects
     or (regexp, request_class) tuples. When we receive requests, we
@@ -1762,7 +1762,7 @@ class Application(httputil.HTTPServerConnectionDelegate):
         `.TCPServer.bind`/`.TCPServer.start` methods directly.
 
         Note that after calling this method you still need to call
-        ``IOLoop.instance().start()`` to start the server.
+        ``IOLoop.current().start()`` to start the server.
         """
         # import is here rather than top level because HTTPServer
         # is not importable on appengine
index e08566afb5280e55eac62f114f4e9049db85ef43..59e6c559f1289695ffc99627ee65ab3398562e5c 100644 (file)
@@ -253,7 +253,7 @@ class WSGIContainer(object):
         container = tornado.wsgi.WSGIContainer(simple_app)
         http_server = tornado.httpserver.HTTPServer(container)
         http_server.listen(8888)
-        tornado.ioloop.IOLoop.instance().start()
+        tornado.ioloop.IOLoop.current().start()
 
     This class is intended to let other frameworks (Django, web.py, etc)
     run on the Tornado HTTP server and I/O loop.