Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Futures and promises

From Wikipedia, the free encyclopedia
Computer science constructs
Not to be confused withPromise theory.

Incomputer science,futures,promises,delays, anddeferreds are constructs used forsynchronizing programexecution in someconcurrent programming languages. Each is an object that acts as a proxy for a result that is initially unknown, usually because thecomputation of its value is not yet complete.

The termpromise was proposed in 1976 byDaniel P. Friedman and David Wise,[1]and Peter Hibbard called iteventual.[2]A somewhat similar conceptfuture was introduced in 1977 in a paper byHenry Baker andCarl Hewitt.[3]

The termsfuture,promise,delay, anddeferred are often used interchangeably, although some differences in usage betweenfuture andpromise are treated below. Specifically, when usage is distinguished, a future is aread-only placeholder view of a variable, while a promise is a writable,single assignment container which sets the value of the future. Notably, a future may be defined without specifying which specific promise will set its value, and different possible promises may set the value of a given future, though this can be done only once for a given future. In other cases a future and a promise are created together and associated with each other: the future is the value, the promise is the function that sets the value – essentially the return value (future) of an asynchronous function (promise). Setting the value of a future is also calledresolving,fulfilling, orbinding it.

Applications

[edit]

Futures and promises originated infunctional programming and related paradigms (such aslogic programming) to decouple a value (a future) from how it was computed (a promise), allowing the computation to be done more flexibly, notably by parallelizing it. Later, it found use indistributed computing, in reducing the latency from communication round trips. Later still, it gained more use by allowing writing asynchronous programs indirect style, rather than incontinuation-passing style.

Implicit vs. explicit

[edit]

Use of futures may beimplicit (any use of the future automatically obtains its value, as if it were an ordinaryreference) orexplicit (the user must call a function to obtain the value, such as theget method ofjava.util.concurrent.FutureinJava). Obtaining the value of an explicit future can be calledstinging orforcing. Explicit futures can be implemented as a library, whereas implicit futures are usually implemented as part of the language.

The original Baker and Hewitt paper described implicit futures, which are naturally supported in theactor model of computation and pureobject-oriented programming languages likeSmalltalk. The Friedman and Wise paper described only explicit futures, probably reflecting the difficulty of efficiently implementing implicit futures on stock hardware. The difficulty is that stock hardware does not deal with futures for primitive data types like integers. For example, an add instruction does not know how to deal with3 +future factorial(100000). In pure actor or object languages this problem can be solved by sendingfuture factorial(100000) the message+[3], which asks the future to add3 to itself and return the result. Note that themessage passing approach works regardless of whenfactorial(100000) finishes computation and that no stinging/forcing is needed.

Promise pipelining

[edit]

The use of futures can dramatically reducelatency indistributed systems. For instance, futures enablepromise pipelining,[4][5] as implemented in the languagesE andJoule, which was also calledcall-stream[6] in the languageArgus.

Consider an expression involving conventionalremote procedure calls, such as:

 t3 := ( x.a() ).c( y.b() )

which could be expanded to

 t1 := x.a(); t2 := y.b(); t3 := t1.c(t2);

Each statement needs a message to be sent and a reply received before the next statement can proceed. Suppose, for example, thatx,y,t1, andt2 are all located on the same remote machine. In this case, two complete network round-trips to that machine must take place before the third statement can begin to execute. The third statement will then cause yet another round-trip to the same remote machine.

Using futures, the above expression could be written

 t3 := (x <- a()) <- c(y <- b())

which could be expanded to

 t1 := x <- a(); t2 := y <- b(); t3 := t1 <- c(t2);

The syntax used here is that of the language E, wherex <- a() means to send the messagea() asynchronously tox. All three variables are immediately assigned futures for their results, and execution proceeds to subsequent statements. Later attempts to resolve the value oft3 may cause a delay; however, pipelining can reduce the number of round-trips needed. If, as in the prior example,x,y,t1, andt2 are all located on the same remote machine, a pipelined implementation can computet3 with one round-trip instead of three. Because all three messages are destined for objects which are on the same remote machine, only one request need be sent and only one response need be received containing the result. The sendt1 <- c(t2) would not block even ift1 andt2 were on different machines to each other, or tox ory.

Promise pipelining should be distinguished from parallel asynchronous message passing. In a system supporting parallel message passing but not pipelining, the message sendsx <- a() andy <- b() in the above example could proceed in parallel, but the send oft1 <- c(t2) would have to wait until botht1 andt2 had been received, even whenx,y,t1, andt2 are on the same remote machine. The relative latency advantage of pipelining becomes even greater in more complicated situations involving many messages.

Promise pipelining also should not be confused withpipelined message processing in actor systems, where it is possible for an actor to specify and begin executing a behaviour for the next message before having completed processing of the current message.

Read-only views

[edit]

In some programming languages such asOz,E, andAmbientTalk, it is possible to obtain aread-only view of a future, which allows reading its value when resolved, but does not permit resolving it:

  • In Oz, the!! operator is used to obtain a read-only view.
  • In E and AmbientTalk, a future is represented by a pair of values called apromise/resolver pair. The promise represents the read-only view, and the resolver is needed to set the future's value.
  • In C++ (sinceC++11) astd::future provides a read-only view. The value is set directly by using astd::promise, or set to the result of a function call usingstd::packaged_task orstd::async.
  • In theDojo Toolkit's Deferred API as of version 1.5, aconsumer-only promise object represents a read-only view.[7]
  • InAlice ML, futures provide aread-only view, whereas a promise contains both a future and the ability to resolve the future[8][9]
  • In.NETSystem.Threading.Tasks.Task<T> represents a read-only view. Resolving the value can be done viaSystem.Threading.Tasks.TaskCompletionSource<T>.

Support for read-only views is consistent with theprinciple of least privilege, since it enables the ability to set the value to be restricted tosubjects that need to set it. In a system that also supports pipelining, the sender of an asynchronous message (with result) receives the read-only promise for the result, and the target of the message receives the resolver.

Thread-specific futures

[edit]

Some languages, such asAlice ML, define futures that are associated with a specific thread that computes the future's value.[9] This computation can start eithereagerly when the future is created, orlazily when its value is first needed. A lazy future is similar to athunk, in the sense of a delayed computation.

Alice ML also supports futures that can be resolved by any thread, and calls thesepromises.[8] This use ofpromise is different from its use in E as describedabove. In Alice, a promise is not a read-only view, and promise pipelining is unsupported. Instead, pipelining naturally happens for futures, including ones associated with promises.

Blocking vs non-blocking semantics

[edit]

If the value of a future is accessed asynchronously, for example by sending a message to it, or by explicitly waiting for it using a construct such aswhen in E, then there is no difficulty in delaying until the future is resolved before the message can be received or the wait completes. This is the only case to be considered in purely asynchronous systems such as pure actor languages.

However, in some systems it may also be possible to attempt toimmediately orsynchronously access a future's value. Then there is a design choice to be made:

  • the access could block the current thread or process until the future is resolved (possibly with a timeout). This is the semantics ofdataflow variables in the languageOz.
  • the attempted synchronous access could always signal an error, for example throwing anexception. This is the semantics of remote promises in E.[10]
  • potentially, the access could succeed if the future is already resolved, but signal an error if it is not. This would have the disadvantage of introducing nondeterminism and the potential forrace conditions, and seems to be an uncommon design choice.

As an example of the first possibility, inC++11, a thread that needs the value of a future can block until it is available by calling thewait() orget() member functions. A timeout can also be specified on the wait using thewait_for() orwait_until() member functions to avoid indefinite blocking. If the future arose from a call tostd::async then a blocking wait (without a timeout) may cause synchronous invocation of the function to compute the result on the waiting thread.

Related constructs

[edit]

Futures are a particular case of thesynchronization primitive "events," which can be completed only once. In general, events can be reset to initial empty state and, thus, completed as many times as desired.[11]

AnI-var (as in the languageId) is a future with blocking semantics as defined above. AnI-structure is adata structure containing I-vars. A related synchronization construct that can be set multiple times with different values is called anM-var. M-vars support atomic operations totake orput the current value, where taking the value also sets the M-var back to its initialempty state.[12]

Aconcurrent logic variable[citation needed] is similar to a future, but is updated byunification, in the same way aslogic variables inlogic programming. Thus it can be bound more than once to unifiable values, but cannot be set back to an empty or unresolved state. The dataflow variables of Oz act as concurrent logic variables, and also have blocking semantics as mentioned above.

Aconcurrent constraint variable is a generalization of concurrent logic variables to supportconstraint logic programming: the constraint may benarrowed multiple times, indicating smaller sets of possible values. Typically there is a way to specify a thunk that should run whenever the constraint is narrowed further; this is needed to supportconstraint propagation.

Relations between the expressiveness of different forms of future

[edit]

Eager thread-specific futures can be straightforwardly implemented in non-thread-specific futures, by creating a thread to calculate the value at the same time as creating the future. In this case it is desirable to return a read-only view to the client, so that only the newly created thread is able to resolve this future.

To implement implicit lazy thread-specific futures (as provided by Alice ML, for example) in terms in non-thread-specific futures, needs a mechanism to determine when the future's value is first needed (for example, theWaitNeeded construct in Oz[13]). If all values are objects, then the ability to implement transparent forwarding objects is sufficient, since the first message sent to the forwarder indicates that the future's value is needed.

Non-thread-specific futures can be implemented in thread-specific futures, assuming that the system supports message passing, by having the resolving thread send a message to the future's own thread. However, this can be viewed as unneeded complexity. In programming languages based on threads, the most expressive approach seems to be to provide a mix of non-thread-specific futures, read-only views, and either aWaitNeeded construct, or support for transparent forwarding.

Evaluation strategy

[edit]
Further information:Call by future

Theevaluation strategy of futures, which may be termedcall by future, is non-deterministic: the value of a future will be evaluated at some time between when the future is created and when its value is used, but the precise time is not determined beforehand and can change from run to run. The computation can start as soon as the future is created (eager evaluation) or only when the value is actually needed (lazy evaluation), and may be suspended part-way through, or executed in one run. Once the value of a future is assigned, it is not recomputed on future accesses; this is like thememoization used incall by need.

Alazy future is a future that deterministically has lazy evaluation semantics: the computation of the future's value starts when the value is first needed, as in call by need. Lazy futures are of use in languages which evaluation strategy is by default not lazy. For example, inC++11 such lazy futures can be created by passing thestd::launch::deferred launch policy tostd::async, along with the function to compute the value.

Semantics of futures in the actor model

[edit]

In the actor model, an expression of the formfuture <Expression> is defined by how it responds to anEval message with environmentE and customerC as follows: The future expression responds to theEval message by sending the customerC a newly created actorF (the proxy for the response of evaluating<Expression>) as a return valueconcurrently with sending<Expression> anEval message with environmentE and customerC. The default behavior ofF is as follows:

  • WhenF receives a requestR, then it checks to see if it has already received a response (that can either be a return value or a thrown exception) from evaluating<Expression> proceeding as follows:
    1. If it already has a responseV, then
      • IfV is a return value, then it is sent the requestR.
      • IfV is an exception, then it is thrown to the customer of the requestR.
    2. If it does not already have a response, thenR is stored in the queue of requests inside theF.
  • WhenF receives the responseV from evaluating<Expression>, thenV is stored inF and
    • IfV is a return value, then all of the queued requests are sent toV.
    • IfV is an exception, then it is thrown to the customer of each of the queued requests.

However, some futures can deal with requests in special ways to provide greater parallelism. For example, the expression1 + future factorial(n) can create a new future that will behave like the number1+factorial(n). This trick does not always work. For example, the following conditional expression:

if m>future factorial(n)then print("bigger")else print("smaller")

suspends until the future forfactorial(n) has responded to the request asking ifm is greater than itself.

History

[edit]

Thefuture and/orpromise constructs were first implemented in programming languages such asMultiLisp andAct 1. The use of logic variables for communication inconcurrentlogic programming languages was quite similar to futures. These began inProlog with Freeze andIC Prolog, and became a true concurrency primitive with Relational Language, ConcurrentProlog, guardedHorn clauses (GHC),Parlog,Strand,Vulcan,Janus,Oz-Mozart,Flow Java, andAlice ML. The single-assignmentI-var fromdataflow programming languages, originating inId and included in Reppy'sConcurrent ML, is much like the concurrent logic variable.

The promise pipelining technique (using futures to overcome latency) was invented byBarbara Liskov andLiuba Shrira in 1988,[6] and independently byMark S. Miller, Dean Tribble and Rob Jellinghaus in the context ofProject Xanadu circa 1989.[14]

The termpromise was coined by Liskov and Shrira, although they referred to the pipelining mechanism by the namecall-stream, which is now rarely used.

Both the design described in Liskov and Shrira's paper, and the implementation of promise pipelining in Xanadu, had the limit that promise values were notfirst-class: an argument to, or the value returned by a call or send could not directly be a promise (so the example of promise pipelining given earlier, which uses a promise for the result of one send as an argument to another, would not have been directly expressible in the call-stream design or in the Xanadu implementation). It seems that promises and call-streams were never implemented in any public release of Argus,[15] the programming language used in the Liskov and Shrira paper. Argus development stopped around 1988.[16] The Xanadu implementation of promise pipelining only became publicly available with the release of the source code for Udanax Gold[17] in 1999, and was never explained in any published document.[18] The later implementations in Joule and E support fully first-class promises and resolvers.

Several early actor languages, including the Act series,[19][20] supported both parallel message passing and pipelined message processing, but not promise pipelining. (Although it is technically possible to implement the last of these features in the first two, there is no evidence that the Act languages did so.)

After 2000, a major revival of interest in futures and promises occurred, due to their use inresponsiveness of user interfaces, and inweb development, due to therequest–response model of message-passing. Several mainstream languages now have language support for futures and promises, most notably popularized byFutureTask in Java 5 (announced 2004)[21] and theasync/await constructions in .NET 4.5 (announced 2010, released 2012)[22][23] largely inspired by theasynchronous workflows of F#,[24] which dates to 2007.[25] This has subsequently been adopted by other languages, notably Dart (2014),[26] Python (2015),[27] Hack (HHVM), and drafts of ECMAScript 7 (JavaScript), Scala, and C++ (2011).

List of implementations

[edit]

Some programming languages are supporting futures, promises, concurrent logic variables, dataflow variables, or I-vars, either by direct language support or in the standard library.

List of concepts related to futures and promises by programming language

[edit]

Languages also supporting promise pipelining include:

List of library-based implementations of futures

[edit]

Coroutines

[edit]

Futures can be implemented incoroutines[27] orgenerators,[103] resulting in the same evaluation strategy (e.g.,cooperative multitasking or lazy evaluation).

Channels

[edit]
Main article:Channel (programming)

Futures can easily be implemented inchannels: a future is a one-element channel, and a promise is a process that sends to the channel, fulfilling the future.[104][105] This allows futures to be implemented in concurrent programming languages with support for channels, such as CSP andGo. The resulting futures are explicit, as they must be accessed by reading from the channel, rather than only evaluation.

See also

[edit]

References

[edit]
  1. ^Friedman, Daniel; David Wise (1976).The Impact of Applicative Programming on Multiprocessing. International Conference on Parallel Processing. pp. 263–272.
    Preliminary version of:Friedman, Daniel; Wise, David (April 1978). "Aspects of Applicative Programming for Parallel Processing".IEEE Transactions on Computers.C-27 (4):289–296.CiteSeerX 10.1.1.295.9692.doi:10.1109/tc.1978.1675100.S2CID 16333366.
  2. ^Hibbard, Peter (1976).Parallel Processing Facilities. New Directions in Algorithmic Languages, (ed.) Stephen A. Schuman, IRIA, 1976.
  3. ^Henry Baker; Carl Hewitt (August 1977).The Incremental Garbage Collection of Processes. Proceedings of the Symposium on Artificial Intelligence Programming Languages. ACM SIGPLAN Notices 12, 8. pp. 55–59. Archived fromthe original on 4 July 2008. Retrieved13 February 2015.
  4. ^Promise Pipelining at erights.org
  5. ^Promise Pipelining on the C2 wiki
  6. ^abBarbara Liskov; Liuba Shrira (1988). "Promises: Linguistic Support for Efficient Asynchronous Procedure Calls in Distributed Systems".Proceedings of the SIGPLAN '88 Conference on Programming Language Design and Implementation; Atlanta, Georgia, United States. ACM. pp. 260–267.doi:10.1145/53990.54016.ISBN 0-89791-269-1. Also published inACM SIGPLAN Notices23(7).
  7. ^Robust promises with Dojo deferred, Site Pen, 3 May 2010
  8. ^ab"Promise",Alice Manual, DE: Uni-SB, archived fromthe original on 8 October 2008, retrieved21 March 2007
  9. ^ab"Future",Alice manual, DE: Uni-SB, archived fromthe original on 6 October 2008, retrieved21 March 2007
  10. ^Promise, E rights
  11. ^500 lines or less, "A Web Crawler With asyncio Coroutines" by A. Jesse Jiryu Davis and Guido van Rossum says "implementation uses an asyncio.Event in place of the Future shown here. The difference is an Event can be reset, whereas a Future cannot transition from resolved back to pending."
  12. ^Control Concurrent MVar, Haskell, archived fromthe original on 18 April 2009
  13. ^WaitNeeded, Mozart Oz, archived from the original on 17 May 2013, retrieved21 March 2007
  14. ^Promise, Sunless Sea, archived fromthe original on 23 October 2007
  15. ^Argus, MIT
  16. ^Liskov, Barbara (26 January 2021),Distributed computing and Argus, Oral history, IEEE GHN
  17. ^Gold, Udanax, archived fromthe original on 11 October 2008
  18. ^Pipeline, E rights
  19. ^Henry Lieberman (June 1981). "A Preview of Act 1".MIT AI Memo 625.
  20. ^Henry Lieberman (June 1981). "Thinking About Lots of Things at Once without Getting Confused: Parallelism in Act 1".MIT AI Memo 626.
  21. ^Goetz, Brian (23 November 2004)."Concurrency in JDK 5.0".IBM.
  22. ^ab"Async in 4.5: Worth the Await – .NET Blog – Site Home – MSDN Blogs". Blogs.msdn.com. Retrieved13 May 2014.
  23. ^abc"Asynchronous Programming with Async and Await (C# and Visual Basic)". Msdn.microsoft.com. Retrieved13 May 2014.
  24. ^Tomas Petricek (29 October 2010)."Asynchronous C# and F# (I.): Simultaneous introduction".
  25. ^Don Syme; Tomas Petricek; Dmitry Lomov (21 October 2010)."The F# Asynchronous Programming Model, PADL 2011".
  26. ^abGilad Bracha (October 2014)."Dart Language Asynchrony Support: Phase 1".
  27. ^ab"PEP 0492 – Coroutines with async and await syntax".
  28. ^Kenjiro Taura; Satoshi Matsuoka; Akinori Yonezawa (1994). "ABCL/f: A Future-Based Polymorphic Typed Concurrent Object-Oriented Language – Its Design and Implementation.".In Proceedings of the DIMACS workshop on Specification of Parallel Algorithms, number 18 in Dimacs Series in Discrete Mathematics and Theoretical Computer Science. American Mathematical Society. pp. 275–292.CiteSeerX 10.1.1.23.1161.
  29. ^"Dart SDK dart async Completer".
  30. ^"Task".
  31. ^Steve Dekorte (2005)."Io, The Programming Language".
  32. ^"Using promises". Mozilla Developer Network. Retrieved23 February 2021.
  33. ^"Making asynchronous programming easier with async and await". Mozilla Developer Network. Retrieved23 February 2021.
  34. ^Rich Hickey (2009)."changes.txt at 1.1.x from richhickey's clojure".GitHub.
  35. ^"Future – Kotlin Programming Language".
  36. ^Seif Haridi; Nils Franzen."Tutorial of Oz". Mozart Global User Library. Archived from the original on 14 May 2011. Retrieved12 April 2011.
  37. ^Python 3.2 Release
  38. ^Python 3.5 Release
  39. ^"Parallelism with Futures". PLT. Retrieved2 March 2012.
  40. ^"class Promise". raku.org. Retrieved19 August 2022.
  41. ^"Future in std::future - Rust".doc.rust-lang.org. Retrieved16 December 2023.
  42. ^Common Lisp Blackbird
  43. ^Common Lisp Eager Future2
  44. ^Lisp in parallel – A parallel programming library for Common Lisp
  45. ^Common Lisp PCall
  46. ^"Chapter 30. Thread 4.0.0". Retrieved26 June 2013.
  47. ^"Dlib C++ Library #thread_pool". Retrieved26 June 2013.
  48. ^"GitHub – facebook/folly: An open-source C++ library developed and used at Facebook".GitHub. 8 January 2019.
  49. ^"HPX". 10 February 2019.
  50. ^"Threads Slides of POCO"(PDF).
  51. ^"QtCore 5.0: QFuture Class". Qt Project. Archived fromthe original on 1 June 2013. Retrieved26 June 2013.
  52. ^"Seastar". Seastar project. Retrieved22 August 2016.
  53. ^"stlab is the ongoing work of what was Adobe's Software Technology Lab. The Adobe Source Libraries (ASL), Platform Libraries, and new stlab libraries are hosted on github". 31 January 2021.
  54. ^Groovy GParsArchived 12 January 2013 at theWayback Machine
  55. ^Cujo.js
  56. ^JavaScript when.js
  57. ^Promises/A+ specification
  58. ^promises
  59. ^JavaScript MochKit.Async
  60. ^JavaScript Angularjs
  61. ^JavaScript node-promise
  62. ^"JavaScript Q". Archived fromthe original on 31 December 2018. Retrieved8 April 2013.
  63. ^JavaScript RSVP.js
  64. ^YUI JavaScript class library
  65. ^YUI JavaScript promise class
  66. ^JavaScript Bluebird
  67. ^Java JDeferred
  68. ^Java ParSeq
  69. ^Objective-C MAFuture GitHub
  70. ^Objective-C MAFuture mikeash.com
  71. ^Objective-C RXPromise
  72. ^ObjC-CollapsingFutures
  73. ^Objective-C PromiseKit
  74. ^Objective-C objc-promise
  75. ^Objective-C OAPromise
  76. ^OCaml Lazy
  77. ^Perl Future
  78. ^Perl Promises
  79. ^Perl Reflex
  80. ^Perl Promise::ES6
  81. ^"Promise::XS – Fast promises in Perl – metacpan.org".metacpan.org. Retrieved14 February 2021.
  82. ^PHP React/Promise
  83. ^Python built-in implementation
  84. ^pythonfutures
  85. ^"Twisted Deferreds". Archived fromthe original on 6 August 2020. Retrieved29 April 2010.
  86. ^R package future
  87. ^future
  88. ^Concurrent Ruby
  89. ^Ruby Promise gem
  90. ^Ruby libuv
  91. ^"Ruby Celluloid gem". Archived fromthe original on 8 May 2013. Retrieved19 February 2022.
  92. ^Ruby future-resource
  93. ^futures-rs crate
  94. ^Twitter's util library
  95. ^"Swift Async". Archived fromthe original on 31 December 2018. Retrieved23 June 2014.
  96. ^Swift FutureKit
  97. ^Swift Apple GCD
  98. ^Swift FutureLib
  99. ^bignerdranch/Deferred
  100. ^Thomvis/BrightFutures
  101. ^belozierov/SwiftCoroutine
  102. ^tcl-promise
  103. ^Does async/await solve a real problem?
  104. ^"Go language patterns Futures". Archived fromthe original on 4 December 2020. Retrieved9 February 2014.
  105. ^"Go Language Patterns". Archived fromthe original on 11 November 2020. Retrieved9 February 2014.

External links

[edit]
Retrieved from "https://en.wikipedia.org/w/index.php?title=Futures_and_promises&oldid=1322457706"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp