From b9915973f3522d3feaa862aaacd4d7d269f6fc72 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 27 Jan 2014 09:11:48 +0100 Subject: Issue #20367: Fix behavior of concurrent.futures.as_completed() for duplicate arguments. Patch by Glenn Langford. --- Doc/library/concurrent.futures.rst | 3 ++- Lib/concurrent/futures/_base.py | 6 ++++-- Lib/test/test_concurrent_futures.py | 7 +++++++ Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Doc/library/concurrent.futures.rst b/Doc/library/concurrent.futures.rst index c2f92b3..575b1ea 100644 --- a/Doc/library/concurrent.futures.rst +++ b/Doc/library/concurrent.futures.rst @@ -368,7 +368,8 @@ Module Functions Returns an iterator over the :class:`Future` instances (possibly created by different :class:`Executor` instances) given by *fs* that yields futures as - they complete (finished or were cancelled). Any futures that completed + they complete (finished or were cancelled). Any futures given by *fs* that + are duplicated will be returned once. Any futures that completed before :func:`as_completed` is called will be yielded first. The returned iterator raises a :exc:`TimeoutError` if :meth:`~iterator.__next__` is called and the result isn't available after *timeout* seconds from the diff --git a/Lib/concurrent/futures/_base.py b/Lib/concurrent/futures/_base.py index ca3aebd..d45a404 100644 --- a/Lib/concurrent/futures/_base.py +++ b/Lib/concurrent/futures/_base.py @@ -181,7 +181,8 @@ def as_completed(fs, timeout=None): Returns: An iterator that yields the given Futures as they complete (finished or - cancelled). + cancelled). If any given Futures are duplicated, they will be returned + once. Raises: TimeoutError: If the entire result iterator could not be generated @@ -190,11 +191,12 @@ def as_completed(fs, timeout=None): if timeout is not None: end_time = timeout + time.time() + fs = set(fs) with _AcquireFutures(fs): finished = set( f for f in fs if f._state in [CANCELLED_AND_NOTIFIED, FINISHED]) - pending = set(fs) - finished + pending = fs - finished waiter = _create_and_install_waiters(fs, _AS_COMPLETED) try: diff --git a/Lib/test/test_concurrent_futures.py b/Lib/test/test_concurrent_futures.py index 39230e1..04c4c37 100644 --- a/Lib/test/test_concurrent_futures.py +++ b/Lib/test/test_concurrent_futures.py @@ -344,6 +344,13 @@ class AsCompletedTests: SUCCESSFUL_FUTURE]), completed_futures) + def test_duplicate_futures(self): + # Issue 20367. Duplicate futures should not raise exceptions or give + # duplicate responses. + future1 = self.executor.submit(time.sleep, 2) + completed = [f for f in futures.as_completed([future1,future1])] + self.assertEqual(len(completed), 1) + class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests, unittest.TestCase): pass diff --git a/Misc/ACKS b/Misc/ACKS index ba32f6b..a8bb161 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -703,6 +703,7 @@ Ronan Lamy Torsten Landschoff Ɓukasz Langa Tino Lange +Glenn Langford Andrew Langmead Detlef Lannert Soren Larsen diff --git a/Misc/NEWS b/Misc/NEWS index e8d1a7a..7062211 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -50,6 +50,9 @@ Core and Builtins Library ------- +- Issue #20367: Fix behavior of concurrent.futures.as_completed() for + duplicate arguments. Patch by Glenn Langford. + - Issue #8260: The read(), readline() and readlines() methods of codecs.StreamReader returned incomplete data when were called after readline() or read(size). Based on patch by Amaury Forgeot d'Arc. -- cgit v0.12 From 8b86348dfacf37761ee49a429cb42aff76866333 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 27 Jan 2014 10:07:50 +0100 Subject: asyncio: document add_signal_handler/remove_signal_handler, add an example for signals --- Doc/library/asyncio-eventloop.rst | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/Doc/library/asyncio-eventloop.rst b/Doc/library/asyncio-eventloop.rst index 953fa49..75df87b 100644 --- a/Doc/library/asyncio-eventloop.rst +++ b/Doc/library/asyncio-eventloop.rst @@ -325,6 +325,29 @@ Run subprocesses asynchronously using the :mod:`subprocess` module. This method returns a :ref:`coroutine object `. +UNIX signals +------------ + +Availability: UNIX only. + +.. method:: BaseEventLoop.add_signal_handler(signum, callback, \*args) + + Add a handler for a signal. + + Raise :exc:`ValueError` if the signal number is invalid or uncatchable. + Raise :exc:`RuntimeError` if there is a problem setting up the handler. + +.. method:: BaseEventLoop.remove_signal_handler(sig) + + Remove a handler for a signal. + + Return ``True`` if a signal handler was removed, ``False`` if not. + +.. seealso:: + + The :mod:`signal` module. + + Executor -------- @@ -381,3 +404,27 @@ Print ``Hello World`` every two seconds, using a callback:: :ref:`Hello World example using a coroutine `. + +Example: Set signal handlers for SIGINT and SIGTERM +--------------------------------------------------- + +Register handlers for signals :py:data:`SIGINT` and :py:data:`SIGTERM`:: + + import asyncio + import functools + import os + import signal + + def ask_exit(signame): + print("got signal %s: exit" % signame) + loop.stop() + + loop = asyncio.get_event_loop() + for signame in ('SIGINT', 'SIGTERM'): + loop.add_signal_handler(getattr(signal, signame), + functools.partial(ask_exit, signame)) + + print("Event loop running forever, press CTRL+c to interrupt.") + print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid()) + loop.run_forever() + -- cgit v0.12