Tasks
Tasks provide stateless fine-grained concurrency to Encore, which may lead to parallelism under certain circumstances.
A task executes an expression in parallel, returning immediately a
future. Tasks can be spawned directly using the async
keyword,
or via the standard library Task.enc
.
For example, an active object can spawn a task inside one of its methods to increase the parallelism in the system, e.g.:
active class Actor
def readNews(): String
val bbc = async(fetchURLContent("http://bbc.com")) ~~> scrapHTML
val dn = async(fetchURLContent("http://dn.se"))~~> scrapHTML
bbc.await()
dn.await()
this.presentInformation(get(bbc), get(dn))
end
end
The async
construct can also be used with blocks:
val bbc = async
val content = fetchURLContent("http://bbc.com")
scrapHTML(content)
end
Tasks do not spawn a new physical thread but a logical one, similar to actors. It is an abstraction detail whether a task spawns an actor or uses any other means.
Tasks are scheduled alongside of actors, and do not get special privileges. Note that tasks will not run in parallel unless the system is under-saturated, because tasks are queued on the same thread as the actor/task that spawned it, and will only run in parallel due to work-stealing.
Tasks can only refer to object instances with safe modes
(active
, read
) and primitive types. For instance, the
following example is allowed:
import Task
read trait NewspaperT
require val web: String
def fetchURLContent(): String
-- fetch the content. simplification (e.g)
"<b>BBC</b>"
end
end
read class Newspaper : NewspaperT
val web: String
def init(web: String): unit
this.web = web
end
end
active class Main
def main() : unit
var newspaper = new Newspaper("http://bbc.com")
async(newspaper.fetchURLContent())
end
end
The type system makes sure that the Encore programming language is always free of data races, even in the presence of tasks, actors, hot objects and ParT types (Encore does not prevent deadlocks).
However, this other one is not allowed:
import Task
read trait NewspaperT
require val web: String
def fetchURLContent(): String
-- fetch the content. simplification (e.g)
"<b>BBC</b>"
end
end
linear class Newspaper : NewspaperT
val web: String
def init(web: String): unit
this.web = web
end
end
active class Main
def main() : unit
var newspaper = new Newspaper("http://bbc.com")
async(newspaper.fetchURLContent())
end
end
As the compiler throws an error in the lines of:
*** Error during capturechecking ***
"test.enc" (line 22, column 5)
Cannot capture variable 'newspaper' of linear type 'Newspaper' in a closure
In expression:
async(newspaper.fetchURLContent())
This is because the Newspaper
class uses now a linear
mode,
which is not a safe mode.