Differences

This shows you the differences between the selected revision and the current version of the page.

at:tutorial:actors 2008/11/04 10:11 at:tutorial:actors 2020/02/05 21:26 current
Line 1: Line 1:
- 
====== Concurrent Programming with Actors ====== ====== Concurrent Programming with Actors ======
Line 179: Line 178:
As you may have noticed previously, asynchronous message sends do not return any value (that is, they return ''nil''). Quite often, the developer is required to work around this lack of return values by means of e.g. explicit customer objects, as shown previously in the calculator example. This, however, leads to less expressive, more difficult to understand code, where the control flow quickly becomes implicit. As you may have noticed previously, asynchronous message sends do not return any value (that is, they return ''nil''). Quite often, the developer is required to work around this lack of return values by means of e.g. explicit customer objects, as shown previously in the calculator example. This, however, leads to less expressive, more difficult to understand code, where the control flow quickly becomes implicit.
 +
 +
 +
==== The Concept ==== ==== The Concept ====
-The most well-known language feature in concurrent and distributed languages (for example, in ABCL, the actor-based concurrent language) to reconcile return values with asynchronous message sends is the notion of a  [[Wp>Future_(programming)|future]]. Futures are also commonly known by the name of //promises// (this is how they are called in the [[http://www.erights.org|E language]] and in Argus). Futures are objects that represent return values that may not yet have been computed. Once the asynchronously invoked method has completed, the future is replaced with the actual return value, and objects that referred to the future transparently refer to the return value.+The most well-known language feature in concurrent and distributed languages (for example, in ABCL, the actor-based concurrent language) to reconcile return values with asynchronous message sends is the notion of a  [[Wp>Future_(programming)|future]]. Futures are also commonly known by the name of //promises// (this is how they are called in the [[http://www.erights.org|E language]] and in Argus). Wikipedia has [[Wp>Futures_and_promises|an excellent article]] about promises, futures and their differences. 
 + 
 +Futures are objects that represent return values that may not yet have been computed. Once the asynchronously invoked method has completed, the future is replaced with the actual return value, and objects that referred to the future transparently refer to the return value.
Using futures, it is possible to re-implement the previous example of requesting our calculator actor to add two numbers as follows: Using futures, it is possible to re-implement the previous example of requesting our calculator actor to add two numbers as follows:
Line 189: Line 193:
def sum := calculator<-add(1,2); def sum := calculator<-add(1,2);
</code> </code>
 +
==== Enabling futures ==== ==== Enabling futures ====
Line 201: Line 206:
</code> </code>
-The first statement imports the futures module into the current lexical scope. This enables you as a developer to use some additional language constructs exported by the futures module, as will be explained later. The second statement enables the futures behaviour, causing any asynchronous message send to return a future rather than ''nil''. If ''false'' is passed to the call to ''enableFutures'', only messages marked explicitly as a ''FutureMessage'' will return a future.+The first statement imports the futures module into the current lexical scope. This enables you as a developer to use some additional language constructs exported by the futures module, as will be explained later. The second statement enables the futures behaviour, causing any asynchronous message send to return a future rather than ''nil''. If ''false'' is passed to the call to ''enableFutures'', only messages annotated explicitly as ''@FutureMessage'' (or as ''@TwoWay'') will return a future.
-More information pertaining to the API of the futures language module can be found in the [[:at:tutorial:appendix#futures_and_multifutures|appendix]].+<note> 
 +In what follows we provide an overview on how to work with futures. More information pertaining to the API of the futures language module can be found in the [[:at:tutorial:appendix#futures_and_multifutures|appendix]]. 
 +</note>
==== Working with Unresolved Futures ==== ==== Working with Unresolved Futures ====
Line 306: Line 313:
As previously explained, there are two modes for enabling futures in AmbientTalk. Invoking ''enableFutures(true)'' makes asynchronous sends return a future by default. Invoking ''enableFutures(false)'' returns ''nil'' by default. No matter how you enabled futures, you can always override the default setting by explicitly //annotating// the message send itself by means of two type tags exported by the futures module, as explained below. As previously explained, there are two modes for enabling futures in AmbientTalk. Invoking ''enableFutures(true)'' makes asynchronous sends return a future by default. Invoking ''enableFutures(false)'' returns ''nil'' by default. No matter how you enabled futures, you can always override the default setting by explicitly //annotating// the message send itself by means of two type tags exported by the futures module, as explained below.
-When a message send is annotated with the ''OneWayMessage'' type tag, it will never attach a future to the message. This is primarily useful if you have enabled futures by default, but want to send a one-way message requiring no result. In this case, simply send the message as follows:+When a message send is annotated with the ''OneWay'' type tag, it will never attach a future to the message. This is primarily useful if you have enabled futures by default, but want to send a one-way message requiring no result. In this case, simply send the message as follows:
<code> <code>
-o<-m()@OneWayMessage+o<-m()@OneWay
</code> </code>
-When a message send is annotated with the ''FutureMessage'' type tag, a future is attached to the message, but //only if futures have been enabled//! This is primarily useful if you have enabled futures, but not by default, because you don't want to incur the overhead of future-type message sends on each of the messages sent. In cases where futures become useful, simply send the message as follows:+When a message send is annotated with the ''@FutureMessage'' or ''@TwoWay'' type tag, a future is attached to the message, but //only if futures have been enabled//! This is primarily useful if you have enabled futures, but not by default, because you don't want to incur the overhead of future-type message sends on each of the messages sent. In cases where futures become useful, simply send the message as follows:
<code> <code>
-o<-m()@FutureMessage+o<-m()@TwoWay
</code> </code>
 +
 +When a message send is annotated with the ''@Due'' type tag, the attached future is expected to be resolved before a specified deadline. As shown below, the annotation takes as parameter a timeout value (in milliseconds) relative to the time at which a message is sent. The future is automatically ruined with a ''TimeoutException'' if the timeout elapses before the return value was received. This is primarily useful to have time-based delivery policy guarantees on asynchronous messages.
 +
 +<code>
 +o<-m()@Due(timeout);
 +</code>
 +
 +<note>
 +More details about the ''Due'' annotation can be found in the section about [[distribution#dealing_with_permanent_failures|leased object references]] in the chapter on distributed programming.
 +</note>
Finally, it is possible to first invoke ''enableFutures(false)'' and later enable it by default anyway by invoking ''enableFutures(true)''. However, once futures have been enabled by default, they can no longer be "turned off" by default. The reason for this is that if two separate files load the futures module and one enables futures by default and the other does not, then the net result is that they will be enabled by default, which will make both applications work correctly. If futures could be disabled, this can cause one object to unexpectedly make other objects crash because they depend on futures. Finally, it is possible to first invoke ''enableFutures(false)'' and later enable it by default anyway by invoking ''enableFutures(true)''. However, once futures have been enabled by default, they can no longer be "turned off" by default. The reason for this is that if two separate files load the futures module and one enables futures by default and the other does not, then the net result is that they will be enabled by default, which will make both applications work correctly. If futures could be disabled, this can cause one object to unexpectedly make other objects crash because they depend on futures.
Line 469: Line 486:
</code> </code>
-If both the ''outer'' and ''inner'' actors lexically see ''x'', they could modify it concurrently, reintroducing race conditions on the internal state of an actor. Therefore, when defining an actor using a block of code, we disallow access to the enclosing lexical scope by the new actor. It is as if it was defined at top-level. Hence, actors behave similarly to [[#isolates|isolates]] in this respect. The above example is incorrect in that ''inner'' will not be able to read or modify ''x''.+If both the ''outer'' and ''inner'' actors lexically see ''x'', they could modify it concurrently, reintroducing race conditions on the internal state of an actor. Therefore, when defining an actor using a block of code, we disallow direct access to the enclosing lexical scope by the new actor. Actors behave similarly to [[#isolates|isolates]] in this respect. The above example code will work, but the programmer has to keep in mind that the ''x'' variable accessed by ''inner'' is a //copy// of the ''x'' variable of ''outer''. Hence, assignments to ''x'' by ''inner'' will not affect ''outer'' and vice versa.
-Recall that isolates could be given selective access to their enclosing lexical scope by specifying accessed variables as formal parameters to their initializing closure, which gave rise to copying the variable into the isolate. We allow actors to do the same. Hence, the above example can be written properly as:+Recall that isolates could be given access to their enclosing lexical scope either by specifying accessed variables as formal parameters to their initializing closure or by having the interpreter derive the lexically free variables automatically. If the programmer wants to make explicit the fact that ''x'' is copied, the example can also be rewritten as:
<code> <code>
 
 
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki