You are on page 1of 13

Python (/)

>>> Python Developer's Guide (/dev/) >>> PEP Index (/dev/peps/) >>> 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)
Motivation (#motivation)
Specification (#specification)
Naming (#naming)
Interface (#interface)
Executor (#executor)
ProcessPoolExecutor (#processpoolexecutor)
ThreadPoolExecutor (#threadpoolexecutor)
Future Objects (#future-objects)
Internal Future Methods (#internal-future-methods)
Module Functions (#module-functions)
Check Prime Example (#check-prime-example)
Web Crawl Example (#web-crawl-example)
Rationale (#rationale)
Reference Implementation (#reference-implementation)

References (#references)
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 __future__ import x" idiom which has been in use for a long time within Python.
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.
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
Noneornotgiventhenasmanyworkerprocesseswillbecreatedasthemachinehasprocessors.

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:

importtime
defwait_on_b():
time.sleep(5)
print(b.result())#bwillnevercompletebecauseitiswaitingona.
return5
defwait_on_a():
time.sleep(5)
print(a.result())#awillnevercompletebecauseitiswaitingonb.
return6

executor=ThreadPoolExecutor(max_workers=2)
a=executor.submit(wait_on_b)
b=executor.submit(wait_on_a)

And:

defwait_on_future():
f=executor.submit(pow,5,2)
#Thiswillnevercompletebecausethereisonlyoneworkerthreadand
#itisexecutingthisfunction.
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.IftimeoutisnotspecifiedorNonethenthereisnolimittothewaittime.
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)

SetstheresultoftheworkassociatedwiththeFuture.

set_exception(exception)

SetstheresultoftheworkassociatedwiththeFuturetothegivenException.

Module Functions (#id27)


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

WaitfortheFutureinstances(possiblycreatedbydifferentExecutorinstances)givenbyfsto
complete.Returnsanamed2tupleofsets.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

as_completed(fs,timeout=None)

Themethodwillreturnwhenallcallsfinish.

ReturnsaniteratorovertheFutureinstancesgivenbyfsthatyieldsfuturesastheycomplete
(finishedorwerecancelled).Anyfuturesthatcompletedbeforeas_completed()wascalledwillbe
yieldedfirst.ThereturnediteratorraisesaTimeoutErrorif__next__()iscalledandtheresult
isn'tavailableaftertimeoutsecondsfromtheoriginalcalltoas_completed().Iftimeoutisnot
specifiedorNonethenthereisnolimittothewaittime.
TheFutureinstancescanhavebeencreatedbydifferentExecutorinstances.

Check Prime Example (#id28)

fromconcurrentimportfutures
importmath
PRIMES=[
112272535095293,
112582705942171,
112272535095293,
115280095190773,
115797848077099,
1099726899285419]
defis_prime(n):
ifn%2==0:
returnFalse
sqrt_n=int(math.floor(math.sqrt(n)))
foriinrange(3,sqrt_n+1,2):
ifn%i==0:
returnFalse
returnTrue
defmain():
withfutures.ProcessPoolExecutor()asexecutor:
fornumber,primeinzip(PRIMES,executor.map(is_prime,
PRIMES)):
print('%disprime:%s'%(number,prime))
if__name__=='__main__':
main()

Web Crawl Example (#id29)

fromconcurrentimportfutures
importurllib.request
URLS=['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://somemadeupdomain.com/']
defload_url(url,timeout):
returnurllib.request.urlopen(url,timeout=timeout).read()
defmain():
withfutures.ThreadPoolExecutor(max_workers=5)asexecutor:
future_to_url=dict(
(executor.submit(load_url,url,60),url)
forurlinURLS)
forfutureinfutures.as_completed(future_to_url):
url=future_to_url[future]
try:
print('%rpageis%dbytes'%(
url,len(future.result())))
exceptExceptionase:
print('%rgeneratedanexception:%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 Python3000 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
The 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
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]

java.util.concurrent package documentation http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-

(#id1)

summary.html (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/package-summary.html)

[2]

Python Cookbook recipe 84317, "Easy threading with Futures" http://code.activestate.com/recipes/84317/

(#id2)

(http://code.activestate.com/recipes/84317/)

[3]

Python-3000 thread, "mechanism for handling asynchronous concurrency" http://mail.python.org/pipermail/python-

(#id3)

3000/2006-April/000960.html (http://mail.python.org/pipermail/python-3000/2006-April/000960.html)

[4]

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

(#id4)

http://mail.python.org/pipermail/python-3000/2006-April/000970.html (http://mail.python.org/pipermail/python-3000/2006April/000970.html)

[5]

A discussion of stream , a similar concept proposed by Anh Hai Trinh http://www.mail-archive.com/stdlib-

(#id5)

sig@python.org/msg00480.html (http://www.mail-archive.com/stdlib-sig@python.org/msg00480.html)

[6]

A discussion of the proposed API on stdlib-sig http://mail.python.org/pipermail/stdlib-sig/2009-November/000731.html

(#id6)

(http://mail.python.org/pipermail/stdlib-sig/2009-November/000731.html)

[7]

A discussion of the PEP on python-dev http://mail.python.org/pipermail/python-dev/2010-March/098169.html

(#id7)

(http://mail.python.org/pipermail/python-dev/2010-March/098169.html)

[8]

Reference futures implementation http://code.google.com/p/pythonfutures/source/browse/#svn/branches/feedback

(#id8)

(http://code.google.com/p/pythonfutures/source/browse/#svn/branches/feedback)

Copyright (#id33)
This document has been placed in the public domain.
Source: https://hg.python.org/peps/file/tip/pep-3148.txt (https://hg.python.org/peps/file/tip/pep-3148.txt)

Tweets by @ThePSF

The PSF
The Python Software Foundation is the organization behind Python. Become a member of the PSF and help advance the
software and our mission.

Back to Top
Back to Top

Copyright 2001-2015. Python Software Foundation Legal Statements Privacy Policy

You might also like