Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4d07189

Browse files
hellysmile1st1
authored andcommitted
bpo-31556: asyncio.wait_for can cancel futures faster with timeout <= 0 (#3703)
1 parent 11045c9 commit 4d07189

3 files changed

Lines changed: 80 additions & 0 deletions

File tree

Lib/asyncio/tasks.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,15 @@ def wait_for(fut, timeout, *, loop=None):
334334
if timeout is None:
335335
return (yield from fut)
336336

337+
if timeout <= 0:
338+
fut = ensure_future(fut, loop=loop)
339+
340+
if fut.done():
341+
return fut.result()
342+
343+
fut.cancel()
344+
raise futures.TimeoutError()
345+
337346
waiter = loop.create_future()
338347
timeout_handle = loop.call_later(timeout, _release_waiter, waiter)
339348
cb = functools.partial(_release_waiter, waiter)

Lib/test/test_asyncio/test_tasks.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,76 @@ def task():
661661
t.cancel()
662662
self.assertRaises(asyncio.CancelledError, loop.run_until_complete, t)
663663

664+
def test_wait_for_timeout_less_then_0_or_0_future_done(self):
665+
def gen():
666+
when = yield
667+
self.assertAlmostEqual(0, when)
668+
669+
loop = self.new_test_loop(gen)
670+
671+
fut = self.new_future(loop)
672+
fut.set_result('done')
673+
674+
ret = loop.run_until_complete(asyncio.wait_for(fut, 0, loop=loop))
675+
676+
self.assertEqual(ret, 'done')
677+
self.assertTrue(fut.done())
678+
self.assertAlmostEqual(0, loop.time())
679+
680+
def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self):
681+
def gen():
682+
when = yield
683+
self.assertAlmostEqual(0, when)
684+
685+
loop = self.new_test_loop(gen)
686+
687+
foo_started = False
688+
689+
@asyncio.coroutine
690+
def foo():
691+
nonlocal foo_started
692+
foo_started = True
693+
694+
with self.assertRaises(asyncio.TimeoutError):
695+
loop.run_until_complete(asyncio.wait_for(foo(), 0, loop=loop))
696+
697+
self.assertAlmostEqual(0, loop.time())
698+
self.assertEqual(foo_started, False)
699+
700+
def test_wait_for_timeout_less_then_0_or_0(self):
701+
def gen():
702+
when = yield
703+
self.assertAlmostEqual(0.2, when)
704+
when = yield 0
705+
self.assertAlmostEqual(0, when)
706+
707+
for timeout in [0, -1]:
708+
with self.subTest(timeout=timeout):
709+
loop = self.new_test_loop(gen)
710+
711+
foo_running = None
712+
713+
@asyncio.coroutine
714+
def foo():
715+
nonlocal foo_running
716+
foo_running = True
717+
try:
718+
yield from asyncio.sleep(0.2, loop=loop)
719+
finally:
720+
foo_running = False
721+
return 'done'
722+
723+
fut = self.new_task(loop, foo())
724+
725+
with self.assertRaises(asyncio.TimeoutError):
726+
loop.run_until_complete(asyncio.wait_for(
727+
fut, timeout, loop=loop))
728+
self.assertTrue(fut.done())
729+
# it should have been cancelled due to the timeout
730+
self.assertTrue(fut.cancelled())
731+
self.assertAlmostEqual(0, loop.time())
732+
self.assertEqual(foo_running, False)
733+
664734
def test_wait_for(self):
665735

666736
def gen():
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Cancel asyncio.wait_for future faster if timeout <= 0

0 commit comments

Comments
 (0)