return f
-_null_future = Future()
-_null_future.set_result(None)
+class _NullFuture(object):
+ """_NullFuture resembles a Future that finished with a result of None.
-moment = Future()
+ It's not actually a `Future` to avoid depending on a particular event loop.
+ Handled as a special case in the coroutine runner.
+ """
+ def result(self):
+ return None
+
+ def done(self):
+ return True
+
+
+# _null_future is used as a dummy value in the coroutine runner. It differs
+# from moment in that moment always adds a delay of one IOLoop iteration
+# while _null_future is processed as soon as possible.
+_null_future = _NullFuture()
+
+moment = _NullFuture()
moment.__doc__ = \
"""A special object which may be yielded to allow the IOLoop to run for
one iteration.
``yield None`` (or ``yield`` with no argument) is now equivalent to
``yield gen.moment``.
"""
-moment.set_result(None)
class Runner(object):
.. versionadded:: 4.1
"""
# Lists and dicts containing YieldPoints were handled earlier.
- if yielded is None:
+ if yielded is None or yielded is moment:
return moment
+ elif yielded is _null_future:
+ return _null_future
elif isinstance(yielded, (list, dict)):
return multi(yielded)
elif is_future(yielded):
from __future__ import absolute_import, division, print_function
import socket
+import subprocess
+import sys
+import textwrap
+from tornado.escape import utf8, to_unicode
from tornado import gen
from tornado.iostream import IOStream
from tornado.log import app_log
from tornado.stack_context import NullContext
from tornado.tcpserver import TCPServer
-from tornado.test.util import skipBefore35, exec_test
+from tornado.test.util import skipBefore35, skipIfNonUnix, exec_test, unittest
from tornado.testing import AsyncTestCase, ExpectLog, bind_unused_port, gen_test
c.close()
# Here tearDown() would re-raise the EBADF encountered in the IO loop
+
+
+@skipIfNonUnix
+class TestMultiprocess(unittest.TestCase):
+ # These tests verify that the two multiprocess examples from the
+ # TCPServer docs work. Both tests start a server with three worker
+ # processes, each of which prints its task id to stdout (a single
+ # byte, so we don't have to worry about atomicity of the shared
+ # stdout stream) and then exits.
+ def run_subproc(self, code):
+ proc = subprocess.Popen(sys.executable,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ proc.stdin.write(utf8(code))
+ proc.stdin.close()
+ proc.wait()
+ stdout = proc.stdout.read()
+ proc.stdout.close()
+ if proc.returncode != 0:
+ raise RuntimeError("Process returned %d. stdout=%r" % (
+ proc.returncode, stdout))
+ return to_unicode(stdout)
+
+ def test_single(self):
+ # As a sanity check, run the single-process version through this test
+ # harness too.
+ code = textwrap.dedent("""
+ from __future__ import print_function
+ from tornado.ioloop import IOLoop
+ from tornado.tcpserver import TCPServer
+
+ server = TCPServer()
+ server.listen(0, address='127.0.0.1')
+ IOLoop.current().run_sync(lambda: None)
+ print('012', end='')
+ """)
+ out = self.run_subproc(code)
+ self.assertEqual(''.join(sorted(out)), "012")
+
+ def test_simple(self):
+ code = textwrap.dedent("""
+ from __future__ import print_function
+ from tornado.ioloop import IOLoop
+ from tornado.process import task_id
+ from tornado.tcpserver import TCPServer
+
+ server = TCPServer()
+ server.bind(0, address='127.0.0.1')
+ server.start(3)
+ IOLoop.current().run_sync(lambda: None)
+ print(task_id(), end='')
+ """)
+ out = self.run_subproc(code)
+ self.assertEqual(''.join(sorted(out)), "012")
+
+ def test_advanced(self):
+ code = textwrap.dedent("""
+ from __future__ import print_function
+ from tornado.ioloop import IOLoop
+ from tornado.netutil import bind_sockets
+ from tornado.process import fork_processes, task_id
+ from tornado.ioloop import IOLoop
+ from tornado.tcpserver import TCPServer
+
+ sockets = bind_sockets(0, address='127.0.0.1')
+ fork_processes(3)
+ server = TCPServer()
+ server.add_sockets(sockets)
+ IOLoop.current().run_sync(lambda: None)
+ print(task_id(), end='')
+ """)
+ out = self.run_subproc(code)
+ self.assertEqual(''.join(sorted(out)), "012")