_null_future = Future()
_null_future.set_result(None)
+moment = Future()
+moment.__doc__ = \
+"""A special object which may be yielded to allow the IOLoop to run for
+one iteration.
+
+This is not needed in normal use but it can be helpful in long-running
+coroutines that are likely to yield Futures that are ready instantly.
+
+Usage: ``yield gen.moment``
+
+.. versionadded:: 3.3
+"""
+moment.set_result(None)
class Runner(object):
"""Internal implementation of `tornado.gen.engine`.
start_yield_point()
elif is_future(yielded):
self.future = yielded
- if not self.future.done():
+ if not self.future.done() or self.future is moment:
self.io_loop.add_future(
self.future, lambda f: self.run())
return False
self.assertEqual(result, 42)
self.finished = True
+ @gen_test
+ def test_moment(self):
+ calls = []
+ @gen.coroutine
+ def f(name, yieldable):
+ for i in range(5):
+ calls.append(name)
+ yield yieldable
+ # First, confirm the behavior without moment: each coroutine
+ # monopolizes the event loop until it finishes.
+ immediate = Future()
+ immediate.set_result(None)
+ yield [f('a', immediate), f('b', immediate)]
+ self.assertEqual(''.join(calls), 'aaaaabbbbb')
+
+ # With moment, they take turns.
+ calls = []
+ yield [f('a', gen.moment), f('b', gen.moment)]
+ self.assertEqual(''.join(calls), 'ababababab')
+ self.finished = True
+
+ calls = []
+ yield [f('a', gen.moment), f('b', immediate)]
+ self.assertEqual(''.join(calls), 'abbbbbaaaa')
+
class GenSequenceHandler(RequestHandler):
@asynchronous