Sie sind auf Seite 1von 13

>>> PEP 3148 - futures - execute computations asynchronously

PEP 3148 - futures - execute computations asynchronously

PEP:

3148

Title:

futures - execute computations asynchronously

Author:

Brian Quinlan <brian at sweetapp.com>

Status:

Final

Type:

Standards Track

Created:

16-Oct-2009

Python-Version:

3.2

Post-History:

Contents

Abstract (#abstract)
Abstract (#abstract)

Motivation (#motivation) (#motivation)

Specification (#specification) (#specification)

Naming (#naming)
Naming (#naming)

Interface (#interface) (#interface)

Executor (#executor)
Executor (#executor)

ProcessPoolExecutor (#processpoolexecutor) (#processpoolexecutor)

ThreadPoolExecutor (#threadpoolexecutor) (#threadpoolexecutor)

Future Objects (#future-objects) (#future-objects)

(#threadpoolexecutor) Future Objects (#future-objects) Internal Future Methods (#internal-future-methods) Module

Internal Future Methods (#internal-future-methods)

Module Functions (#module-functions) (#module-functions)

Check Prime Example (#check-prime-example) (#check-prime-example)

Web Crawl Example (#web-crawl-example) (#web-crawl-example)

Rationale (#rationale) (#rationale)

Reference Implementation (#reference-implementation) (#reference-implementation)

References (#references) (#references)

Copyright (#copyright) (#copyright)

Abstract (#id17)

This PEP proposes a design for a package that facilitates the evaluation of callables using threads and processes.

Motivation (#id18)

Python currently has powerful primitives to construct multi-threaded and multi-process applications but parallelizing simple operations requires a lot of work i.e. explicitly launching processes/threads, constructing a work/results queue, and waiting for completion or some other termination condition (e.g. failure, timeout). It is also difficult to design an application with a global process/thread limit when each component invents its own parallel execution strategy.

Specification (#id19)

Naming (#id20)

The proposed package would be called "futures" and would live in a new "concurrent" top-level package. The rationale behind pushing the futures library into a "concurrent" namespace has multiple components. The first, most simple one is to prevent any

and all confusion with the existing "from

Additionally, it is felt that adding the "concurrent" precursor to the name fully denotes what the library is related to - namely concurrency - this should clear up any addition ambiguity as it has been noted that not everyone in the community is familiar with Java Futures, or the Futures term except as it relates to the US stock market.

future

import x" idiom which has been in use for a long time within Python.

Finally; we are carving out a new namespace for the standard library - obviously named "concurrent". We hope to either add, or move existing, concurrency-related libraries to this in the future. A prime example is the multiprocessing.Pool work, as well as other "addons" included in that module, which work across thread and process boundaries.

Interface (#id21)

The proposed package provides two core classes: Executor and Future . An Executor receives asynchronous work requests (in terms of a callable and its arguments) and returns a Future to represent the execution of that work request.

Executor (#id22)

Executor is an abstract class that provides methods to execute calls asynchronously.

submit(fn, *args, **kwargs)

Schedulesthecallabletobeexecutedasfn(*args, **kwargs) andreturnsaFutureinstance representingtheexecutionofthecallable.

ThisisanabstractmethodandmustbeimplementedbyExecutorsubclasses.

map(func, *iterables, timeout=None)

Equivalenttomap(func, *iterables) butfuncisexecutedasynchronouslyandseveralcallsto funcmaybemadeconcurrently.ThereturnediteratorraisesaTimeoutErrorif next ()is calledandtheresultisn'tavailableaftertimeoutsecondsfromtheoriginalcalltomap().Iftimeout isnotspecifiedorNonethenthereisnolimittothewaittime.Ifacallraisesanexceptionthenthat exceptionwillberaisedwhenitsvalueisretrievedfromtheiterator.

shutdown(wait=True)

Signaltheexecutorthatitshouldfreeanyresourcesthatitisusingwhenthecurrentlypending

futuresaredoneexecuting.CallstoExecutor.submitandExecutor.mapandmadeaftershutdown

willraiseRuntimeError.

IfwaitisTruethenthismethodwillnotreturnuntilallthependingfuturesaredoneexecutingand

theresourcesassociatedwiththeexecutorhavebeenfreed.IfwaitisFalsethenthismethodwill

returnimmediatelyandtheresourcesassociatedwiththeexecutorwillbefreedwhenallpending

futuresaredoneexecuting.Regardlessofthevalueofwait,theentirePythonprogramwillnotexit

untilallpendingfuturesaredoneexecuting.

enter

()

exit

(exc_type,

exc_val, exc_tb)

Whenusinganexecutorasacontextmanager, exit willcall Executor.shutdown(wait=True) .

ProcessPoolExecutor (#id23)

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 pickleable according to the same limitations as the multiprocessing module.

Calling Executor or Future methods from within a callable submitted to a ProcessPoolExecutor will result in deadlock.

init

(max_workers)

Executescallsasynchronouslyusingapoolofamostmax_workersprocesses.Ifmax_workersis None ornotgiventhenasmanyworkerprocesseswillbecreatedasthemachinehasprocessors.

ThreadPoolExecutor (#id24)

The ThreadPoolExecutor class is an Executor subclass that uses a pool of threads to execute calls asynchronously.

Deadlock can occur when the callable associated with a Future waits on the results of another Future . For example:

import time def wait_on_b():

time.sleep(5)

print(b.result()) # b will never complete because it is waiting on a. return 5

def wait_on_a():

time.sleep(5)

print(a.result()) # a will never complete because it is waiting on b. return 6

executor = ThreadPoolExecutor(max_workers=2)

a = executor.submit(wait_on_b)

b = executor.submit(wait_on_a)

And:

def wait_on_future():

f = executor.submit(pow, 5, 2)

# This will never complete because there is only one worker thread and

# it is executing this function. print(f.result())

executor = ThreadPoolExecutor(max_workers=1) executor.submit(wait_on_future)

init

(max_workers)

Executescallsasynchronouslyusingapoolofatmostmax_workersthreads.

Future Objects (#id25)

The Future class encapsulates the asynchronous execution of a callable. Future instances are returned by Executor.submit .

cancel()

Attempttocancelthecall.Ifthecalliscurrentlybeingexecutedthenitcannotbecancelledandthe

methodwillreturnFalse,otherwisethecallwillbecancelledandthemethodwillreturnTrue.

cancelled()

ReturnTrueifthecallwassuccessfullycancelled.

running()

ReturnTrueifthecalliscurrentlybeingexecutedandcannotbecancelled.

done()

ReturnTrueifthecallwassuccessfullycancelledorfinishedrunning.

result(timeout=None)

Returnthevaluereturnedbythecall.Ifthecallhasn'tyetcompletedthenthismethodwillwaitup

totimeoutseconds.Ifthecallhasn'tcompletedintimeoutsecondsthenaTimeoutErrorwillbe

raised.IftimeoutisnotspecifiedorNonethenthereisnolimittothewaittime.

IfthefutureiscancelledbeforecompletingthenCancelledErrorwillberaised.

Ifthecallraisedthenthismethodwillraisethesameexception.

exception(timeout=None)

Returntheexceptionraisedbythecall.Ifthecallhasn'tyetcompletedthenthismethodwillwaitup totimeoutseconds.Ifthecallhasn'tcompletedintimeoutsecondsthenaTimeoutErrorwillbe raised.IftimeoutisnotspecifiedorNone thenthereisnolimittothewaittime.

IfthefutureiscancelledbeforecompletingthenCancelledErrorwillberaised.

IfthecallcompletedwithoutraisingthenNoneisreturned.

add_done_callback(fn)

Attachesacallablefntothefuturethatwillbecalledwhenthefutureiscancelledorfinishes

running.fnwillbecalledwiththefutureasitsonlyargument.

Addedcallablesarecalledintheorderthattheywereaddedandarealwayscalledinathread

belongingtotheprocessthataddedthem.IfthecallableraisesanExceptionthenitwillbelogged

andignored.IfthecallableraisesanotherBaseExceptionthenbehaviorisnotdefined.

Ifthefuturehasalreadycompletedorbeencancelledthenfnwillbecalledimmediately.

Internal Future Methods (#id26)

The following Future methods are meant for use in unit tests and Executor implementations.

set_running_or_notify_cancel()

ShouldbecalledbyExecutorimplementationsbeforeexecutingtheworkassociatedwiththe

Future.

IfthemethodreturnsFalsethentheFuturewascancelled,i.e.Future.cancelwascalledand

returnedTrue.AnythreadswaitingontheFuturecompleting(i.e.throughas_completed()or

wait())willbewokenup.

IfthemethodreturnsTruethentheFuturewasnotcancelledandhasbeenputintherunning

state,i.e.callstoFuture.running()willreturnTrue.

ThismethodcanonlybecalledonceandcannotbecalledafterFuture.set_result()or

Future.set_exception()havebeencalled.

set_result(result)

SetstheresultoftheworkassociatedwiththeFuturetothegivenException.

Module Functions (#id27)

wait(fs, timeout=None, return_when=ALL_COMPLETED)

WaitfortheFutureinstances(possiblycreatedbydifferentExecutorinstances)givenbyfsto

complete.Returnsanamed2­tupleofsets.Thefirstset,named"done",containsthefuturesthat

completed(finishedorwerecancelled)beforethewaitcompleted.Thesecondset,named

"not_done",containsuncompletedfutures.

timeoutcanbeusedtocontrolthemaximumnumberofsecondstowaitbeforereturning.Iftimeout

isnotspecifiedorNonethenthereisnolimittothewaittime.

return_whenindicateswhenthemethodshouldreturn.Itmustbeoneofthefollowingconstants:

Constant

Description

FIRST_COMPLETED

Themethodwillreturnwhenanyfuturefinishesoris

cancelled.

FIRST_EXCEPTION

Themethodwillreturnwhenanyfuturefinishesbyraising

anexception.Ifnotfutureraisesanexceptionthenitis

equivalenttoALL_COMPLETED.

ALL_COMPLETED

Themethodwillreturnwhenallcallsfinish.

as_completed(fs, timeout=None)

ReturnsaniteratorovertheFutureinstancesgivenbyfsthatyieldsfuturesastheycomplete (finishedorwerecancelled).Anyfuturesthatcompletedbeforeas_completed()wascalledwillbe yieldedfirst.ThereturnediteratorraisesaTimeoutErrorif next ()iscalledandtheresult isn'tavailableaftertimeoutsecondsfromtheoriginalcalltoas_completed().Iftimeoutisnot specifiedorNonethenthereisnolimittothewaittime.

TheFutureinstancescanhavebeencreatedbydifferentExecutorinstances.

Check Prime Example (#id28)

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 (#id29)

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] try:

print('%r page is %d bytes' % ( url, len(future.result()))) except Exception as e:

print('%r generated an exception: %s' % ( url, e))

if

name

main()

== '

main

':

Rationale (#id30)

The proposed design of this module was heavily influenced by the the Java java.util.concurrent package [1] (#id9) . The conceptual

basis of the module, as in Java, is the Future class, which represents the progress and result of an asynchronous computation. The Future class makes little commitment to the evaluation mode being used e.g. it can be be used to represent lazy or eager evaluation, for evaluation using threads, processes or remote procedure call.

Futures are created by concrete implementations of the Executor class (called ExecutorService in Java). The reference implementation provides classes that use either a process or a thread pool to eagerly evaluate computations.

Futures have already been seen in Python as part of a popular Python cookbook recipe [2] (#id10) and have discussed on the Python-

3000 mailing list [3] (#id11) .

The proposed design is explicit, i.e. it requires that clients be aware that they are consuming Futures. It would be possible to design

a module that would return proxy objects (in the style of weakref ) that could be used transparently. It is possible to build a proxy

implementation on top of the proposed explicit mechanism.

The proposed design does not introduce any changes to Python language syntax or semantics. Special syntax could be introduced

[4] (#id12) to mark function and method calls as asynchronous. A proxy result would be returned while the operation is eagerly

evaluated asynchronously, and execution would only block if the proxy object were used before the operation completed.

Anh Hai Trinh proposed a simpler but more limited API concept [5] (#id13) and the API has been discussed in some detail on stdlib-sig

[6] (#id14) .

The proposed design was discussed on the Python-Dev mailing list [7] (#id15) . Following those discussions, the following changes

were made:

The Executor class was made into an abstract base class Executor class was made into an abstract base class

The Future.remove_done_callback method was removed due to a lack of convincing use cases Future.remove_done_callback method was removed due to a lack of convincing use cases

The Future.add_done_callback method was modified to allow the same callable to be added many times Future.add_done_callback method was modified to allow the same callable to be added many times

The Future class's mutation methods were better documented to indicate that they are private to the Future class's mutation methods were better documented to indicate that they are private to the Executor that created them

Reference Implementation (#id31)

The reference implementation [8] (#id16) contains a complete implementation of the proposed design. It has been tested on Linux

and Mac OS X.

References (#id32)

[1]

(#id1)

[2]

(#id2)

[3]

(#id3)

[4]

(#id4)

April/000970.html)
April/000970.html)

Python 3000 thread, "Futures in Python 3000 (was Re: mechanism for handling asynchronous concurrency)"