diff --git a/pep-3148.txt b/pep-3148.txt index c301a64be..2fb4c12a7 100644 --- a/pep-3148.txt +++ b/pep-3148.txt @@ -33,65 +33,6 @@ when each component invents its own parallel execution strategy. Specification ============= -Check Prime Example -------------------- - -:: - - from concurrent import futures - import math - - PRIMES = [ - 112272535095293, - 112582705942171, - 112272535095293, - 115280095190773, - 115797848077099, - 1099726899285419] - - def is_prime(n): - if n % 2 == 0: - return False - - sqrt_n = int(math.floor(math.sqrt(n))) - for i in range(3, sqrt_n + 1, 2): - if n % i == 0: - return False - return True - - with futures.ProcessPoolExecutor() as executor: - for number, is_prime in zip(PRIMES, executor.map(is_prime, PRIMES)): - print('%d is prime: %s' % (number, is_prime)) - -Web Crawl Example ------------------ - -:: - - from concurrent import futures - import urllib.request - - URLS = ['http://www.foxnews.com/', - 'http://www.cnn.com/', - 'http://europe.wsj.com/', - 'http://www.bbc.co.uk/', - 'http://some-made-up-domain.com/'] - - def load_url(url, timeout): - return urllib.request.urlopen(url, timeout=timeout).read() - - with futures.ThreadPoolExecutor(max_workers=5) as executor: - future_to_url = dict((executor.submit(load_url, url, 60), url) - for url in URLS) - - for future in futures.as_completed(future_to_url): - url = future_to_url[future] - if future.exception() is not None: - print('%r generated an exception: %s' % (url, - future.exception())) - else: - print('%r page is %d bytes' % (url, len(future.result()))) - Interface --------- @@ -111,7 +52,7 @@ asynchronously. Schedules the callable to be executed as ``fn(*args, **kwargs)`` and returns a `Future` instance representing the execution of the - function. + callable. This is an abstract method and must be implemented by Executor subclasses. @@ -134,9 +75,14 @@ asynchronously. Calls to `Executor.submit` and `Executor.map` and made after shutdown will raise `RuntimeError`. - If wait is `True` then the executor will not return until all the + If wait is `True` then this method will not return until all the pending futures are done executing and the resources associated - with the executor have been freed. + with the executor have been freed. If wait is `False` then this + method will return immediately and the resources associated with + the executor will be freed when all pending futures are done + executing. Regardless of the value of wait, the entire Python + program will not exit until all pending futures are done + executing. | ``__enter__()`` | ``__exit__(exc_type, exc_val, exc_tb)`` @@ -151,7 +97,7 @@ ProcessPoolExecutor The `ProcessPoolExecutor` class is an `Executor` subclass that uses a pool of processes to execute calls asynchronously. The callable objects and arguments passed to `ProcessPoolExecutor.submit` must be -serializeable according to the same limitations as the multiprocessing +pickleable according to the same limitations as the multiprocessing module. Calling `Executor` or `Future` methods from within a callable @@ -208,8 +154,7 @@ Future Objects '''''''''''''' The `Future` class encapsulates the asynchronous execution of a -function or method call. `Future` instances are returned by -`Executor.submit`. +callable. `Future` instances are returned by `Executor.submit`. ``cancel()`` @@ -260,22 +205,14 @@ function or method call. `Future` instances are returned by ``add_done_callback(fn)`` - Attaches a function *fn* to the future that will be called when + Attaches a callable *fn* to the future that will be called when the future is cancelled or finishes running. *fn* will be called - with the future as its only argument. + with the future as its only argument. Added callables are called + in the order that they were added and are always called in a + thread belonging to the process that added them. If the future has already completed or been cancelled then *fn* - will be called immediately. If the same function is added several - times then it will still only be called once. - - NOTE: This method can be used to create adapters from Futures to - Twisted Deferreds. - -``remove_done_callback(fn)`` - - Removes the function *fn*, which was previously attached to the - future using `add_done_callback`. `KeyError` is raised if the - function was not previously attached. + will be called immediately. Internal Future Methods ^^^^^^^^^^^^^^^^^^^^^^^ @@ -315,11 +252,12 @@ Module Functions ``wait(fs, timeout=None, return_when=ALL_COMPLETED)`` - Wait for the `Future` instances given by *fs* to complete. - Returns a named 2-tuple of sets. The first set, named "finished", - contains the futures that completed (finished or were cancelled) - before the wait completed. The second set, named "not_finished", - contains uncompleted futures. + Wait for the `Future` instances (possibly created by different + `Executor` instances) given by *fs* to complete. Returns a named + 2-tuple of sets. The first set, named "done", contains the + futures that completed (finished or were cancelled) before the + wait completed. The second set, named "not_done", contains + uncompleted futures. *timeout* can be used to control the maximum number of seconds to wait before returning. If timeout is not specified or None then @@ -350,6 +288,79 @@ Module Functions *timeout* is not specified or `None` then there is no limit to the wait time. + The `Future` instances can have been created by different + `Executor` instances. + +Check Prime Example +------------------- + +:: + + from concurrent import futures + import math + + PRIMES = [ + 112272535095293, + 112582705942171, + 112272535095293, + 115280095190773, + 115797848077099, + 1099726899285419] + + def is_prime(n): + if n % 2 == 0: + return False + + sqrt_n = int(math.floor(math.sqrt(n))) + for i in range(3, sqrt_n + 1, 2): + if n % i == 0: + return False + return True + + def main(): + with futures.ProcessPoolExecutor() as executor: + for number, prime in zip(PRIMES, executor.map(is_prime, + PRIMES)): + print('%d is prime: %s' % (number, prime)) + + if __name__ == '__main__': + main() + +Web Crawl Example +----------------- + +:: + + from concurrent import futures + import urllib.request + + URLS = ['http://www.foxnews.com/', + 'http://www.cnn.com/', + 'http://europe.wsj.com/', + 'http://www.bbc.co.uk/', + 'http://some-made-up-domain.com/'] + + def load_url(url, timeout): + return urllib.request.urlopen(url, timeout=timeout).read() + + def main(): + with futures.ThreadPoolExecutor(max_workers=5) as executor: + future_to_url = dict( + (executor.submit(load_url, url, 60), url) + for url in URLS) + + for future in futures.as_completed(future_to_url): + url = future_to_url[future] + if future.exception() is not None: + print('%r generated an exception: %s' % ( + url, future.exception())) + else: + print('%r page is %d bytes' % ( + url, len(future.result()))) + + if __name__ == '__main__': + main() + ========= Rationale =========