8000 tasks: Fix as_completed, gather & wait to work with duplicate corouti… · python/asyncio@4b34c93 · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Nov 23, 2017. It is now read-only.

Commit 4b34c93

Browse files
committed
tasks: Fix as_completed, gather & wait to work with duplicate coroutines. Issue #114
1 parent b9c2442 commit 4b34c93

File tree

2 files changed

+51
-11
lines changed

2 files changed

+51
-11
lines changed

asyncio/tasks.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ def wait(fs, *, loop=None, timeout=None, return_when=ALL_COMPLETED):
364364
if loop is None:
365365
loop = events.get_event_loop()
366366

367-
fs = set(async(f, loop=loop) for f in fs)
367+
fs = {async(f, loop=loop) for f in set(fs)}
368368

369369
if return_when not in (FIRST_COMPLETED, FIRST_EXCEPTION, ALL_COMPLETED):
370370
raise ValueError('Invalid return_when value: {}'.format(return_when))
@@ -476,7 +476,7 @@ def as_completed(fs, *, loop=None, timeout=None):
476476
"""
477477
loop = loop if loop is not None else events.get_event_loop()
478478
deadline = None if timeout is None else loop.time() + timeout
479-
todo = set(async(f, loop=loop) for f in fs)
479+
todo = {async(f, loop=loop) for f in set(fs)}
480480
completed = collections.deque()
481481

482482
@coroutine
@@ -568,7 +568,8 @@ def gather(*coros_or_futures, loop=None, return_exceptions=False):
568568
prevent the cancellation of one child to cause other children to
569569
be cancelled.)
570570
"""
571-
children = [async(fut, loop=loop) for fut in coros_or_futures]
571+
arg_to_fut = {arg: async(arg, loop=loop) for arg in set(coros_or_futures)}
572+
children = [arg_to_fut[arg] for arg in coros_or_futures]
572573
n = len(children)
573574
if n == 0:
574575
outer = futures.Future(loop=loop)

tests/test_tasks.py

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,21 @@ def foo():
483483

484484
self.assertEqual(res, 42)
485485

486+
def test_wait_duplicate_coroutines(self):
487+
@asyncio.coroutine
488+
def coro(s):
489+
return s
490+
c = coro('test')
491+
492+
task = asyncio.Task(
493+
asyncio.wait([c, c, coro('spam')], loop=self.loop),
494+
loop=self.loop)
495+
496+
done, pending = self.loop.run_until_complete(task)
497+
498+
self.assertFalse(pending)
499+
self.assertEqual(set(f.result() for f in done), {'test', 'spam'})
500+
486501
def test_wait_errors(self):
487502
self.assertRaises(
488503
ValueError, self.loop.run_until_complete,
@@ -757,14 +772,10 @@ def foo():
757772
def test_as_completed_with_timeout(self):
758773

759774
def gen():
760-
when = yield
761-
self.assertAlmostEqual(0.12, when)
762-
when = yield 0
763-
self.assertAlmostEqual(0.1, when)
764-
when = yield 0
765-
self.assertAlmostEqual(0.15, when)
766-
when = yield 0.1
767-
self.assertAlmostEqual(0.12, when)
775+
yield
776+
yield 0
777+
yield 0
778+
yield 0.1
768779
yield 0.02
769780

770781
loop = test_utils.TestLoop(gen)
@@ -840,6 +851,25 @@ def gen():
840851
done, pending = loop.run_until_complete(waiter)
841852
self.assertEqual(set(f.result() for f in done), {'a', 'b'})
842853

854+
def test_as_completed_duplicate_coroutines(self):
855+
@asyncio.coroutine
856+
def coro(s):
857+
return s
< 8000 code>858+
859+
@asyncio.coroutine
860+
def runner():
861+
result = []
862+
c = coro('ham')
863+
for f in asyncio.as_completed({c, c, coro('spam')}, loop=self.loop):
864+
result.append((yield from f))
865+
return result
866+
867+
fut = asyncio.Task(runner(), loop=self.loop)
868+
self.loop.run_until_complete(fut)
869+
result = fut.result()
870+
self.assertEqual(set(result), {'ham', 'spam'})
871+
self.assertEqual(len(result), 2)
872+
843873
def test_sleep(self):
844874

845875
def gen():
@@ -1505,6 +1535,15 @@ def coro():
15051535
gen3.close()
15061536
gen4.close()
15071537

1538+
def test_duplicate_coroutines(self):
1539+
@asyncio.coroutine
1540+
def coro(s):
1541+
return s
1542+
c = coro('abc')
1543+
fut = asyncio.gather(c, c, coro('def'), c, loop=self.one_loop)
1544+
self._run_loop(self.one_loop)
1545+
self.assertEqual(fut.result(), ['abc', 'abc', 'def', 'abc'])
1546+
15081547
def test_cancellation_broadcast(self):
15091548
# Cancelling outer() cancels all children.
15101549
proof = 0

0 commit comments

Comments
 (0)
0