Permalink
Find file
ed163f5 Nov 28, 2016
@jomifred @rbordini
executable file 420 lines (289 sloc) 16.6 KB

Concurrency in Jason

This document presents some Jason features for concurrent programming.

Intentions

Intentions in Jason are somewhat similar to threads in other languages in so far as they also execute concurrently, unless you have customised the intention selection function to alter the default intention scheduling. By default, different intentions are executed in a round-robin fashion, executing only one element of the (topmost) plan body each time the intention is selected.

New intentions are created by:

  1. external events

    • each perceived change in the environment that the agent reacts to starts a new intention

    • another agent delegates a goal (through an achieve message)

  2. initial goals

  3. the !!, |&| and ||| operators (see next section)

For instance, for an agent with the following program

+b(X)    <- !say(hello(X)).
+!say(M) <- .print(M); !say(M).

when it starts to believe in b(a), b(b), and b(c) (by perceiving these beliefs, for example), three events +b(…​) are produced and then three intentions are created and will concurrently print the messages as follows:

hello(a)
hello(b)
hello(c)
hello(a)
hello(b)
hello(c)
....

Agent Language

New intentions

The plan

+!ga <- ...; !!gb; a1; ...

creates a new intention for gb and then executes the action a1. a1 is executed after the creation of the intention for gb and not after the achievement of gb (as it would be the case if ! was used instead of !!). The intention for gb is a new intention and not the same as the intention for ga.

Concurrent plans

Besides the usual sequence operator ;, plan bodies can also use fork and join operators for concurrent execution of plan bodies: |&| and |||. The first is called fork-join-and and the second fork-join-xor.

For instance, in

+!ga <- ...; !gb; ...
+!gb <- ...; (!g1 |&| !g2); a1; …

the two subgoals g1 and g2 will be achieved concurrently by two sub-intentions; when both are finished, the action a1 will be executed.

In the following case,

+!ga <- ...; !gb; ...
+!gb <- ...; (!g1 ||| !g2); a1; ...

the two subgoals g1 and g2 will be also achieved concurrently; however, when one sub-intention is finished, the other is dropped and the action a1 will be executed.

Regarding precedence, the operator |&| has precedence over ||| which has preference over ;. For instance, a plan like:

x; (a;b) |&| (c;d) ||| (e;f); y

would have the following behaviour: . execute x . concurrently execute * a;b * c;d * e;f . execute y when either a,b,c, and d have finished executing concurrently, or when both e and f have finished.

The following cases can be considered when a failure occurs while achieving either g1 or g2:

  1. there is plan failure for the failed subgoal: the failure is handled by that concurrent sub-intention without interference to the other subgoal.

  2. there is no plan failure:

    • in case of fork-join-and: drops also the other subgoal and handles the failure in the achievement of goal gb above as usual.

    • in case of fork-join-xor: ignore the failure (discarding that concurrent sub-intention) and continue to try the other subgoal.

When a .fail_goal(ga) is executed:

  • The sub-intentions for g1 and g2 are dropped,

  • The goal gb is dropped, and

  • the failure of ga is handled as usual.

When a .succeed_goal(gb) is executed:

  • The sub-intentions for g1 and g2 are dropped,

  • The goal gb is dropped, and

  • The plan for ga continues.

Conflicting plans

If some intention cannot interleave its execution with another, the atomic annotation can be used in the label of plans:

@alabel[atomic] // no other intention will run if an intention based on this plan starts running
+!update(X)
   <- -vl(T);   // gets the current value of belief vl
      +vl(T+X). // updates its value

If an atomic plan runs, all its subgoals will be also atomic.

Internal actions

Some internal actions are useful for concurrent programming in Jason:

Configuration

Different concurrency configurations can be set for the Centralised infrastructure in Jason.

The Jason agent reasoning cycle is executed considering three main stages: sense, deliberate, and act. Such stages can be executed in two different configurations:

  1. Synchronously (or sequentially): In this configuration, the stages of the reasoning cycle are executed sequentially. One stage just starts its execution when the previous stage has finished its execution. For example, the deliberate stage only starts after sense.

  2. Asynchronously (or concurrently): In this configuration, the stages of the reasoning cycle are executed concurrently. One stage can start its execution before the (usual) previous stage has finished. For example, an agent can execute its intentions at the same time as new intentions are being produced by the deliberate stage.

Synchronous Reasoning Cycle

One thread per agent

Each agent has its own thread, which means that if the MAS is composed of 100 agents, 100 threads will be created to execute the agents.

In the default configuration of the .mas2j project file

infrastructure: Centralised

the agent’s thread runs each stage every reasoning cycle:

loop
  sense();
  deliberate();
  act();

When some stages must be executed more than once, the number of cycles for each stage must be informed. The parameters in the .mas2j for this configuration are presented below.

infrastructure: Centralised(threaded,
    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>)

and the reasoning cycle is:

loop
  do <NUMBER-CYCLES-SENSE> times:
    sense();
  do <NUMBER-CYCLES-DELIBERATE> times:
    deliberate();
  do <NUMBER-CYCLES-ACT> times:
    act();

<NUMBER-CYCLES-SENSE> is the maximum number of times that the sense stage is executed before the deliberate stage starts its execution. <NUMBER-CYCLES-DELIBERATE> is the maximum number of times that the deliberate stage is executed before the act stage starts its execution. <NUMBER-CYCLES-ACT> is the maximum number of times that the act stage is executed before the sense stage starts its execution.

In the example below, the sense and deliberate stages will be executed only once, while the act stage will be executed at most 5 times.

infrastructure: Centralised(threaded, 1, 1, 5)

If 9999 is informed for the act stage, then, at least one action of each intention will be executed in the act stage.

infrastructure: Centralised(threaded, 1, 1, 9999)

Thread pool

When the number of agents in the MAS is significantly higher than the number of computer cores, it makes more sense to use thread pools in order to minimize the overhead caused by managing many threads. In this configuration, a limited number of threads is used to execute all agents in the MAS. The parameters for this configuration are detailed below.

infrastructure: Centralised(pool, <NUMBER-THREADS>, [NUMBER-REASONING-CYCLES])

or

infrastructure: Centralised(pool, <NUMBER-THREADS>,
    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>,
    [NUMBER-REASONING-CYCLES])

The keyword pool makes the execution platform to create one thread pool with <NUMBER-THREADS> threads. [NUMBER-REASONING-CYCLES] is the maximum number of times that the sequence sense-deliberate-act is executed (default value is 5).

Each time a thread of the pool runs an agent, the following algorithm is executed:

do <NUMBER-REASONING-CYCLES> times:
  do <NUMBER-CYCLES-SENSE> times:
    sense();
  do <NUMBER-CYCLES-DELIBERATE> times:
    deliberate();
  do <NUMBER-CYCLES-ACT> times:
    act();

In the example below, a thread pool with 4 threads is created and each stage will be executed just once.

infrastructure: Centralised(pool,4)

In the example below, a thread pool with 4 threads is created and the sequence sense-deliberate-act is executed at most 5 times.

infrastructure: Centralised(pool,4,5)

In the example below, a thread pool with 4 threads is created, and the sense and deliberate stages are configured to execute just once, while the act stage will be executed at most 5 times.

infrastructure: Centralised(pool,4,1,1,5)

If 9999 is informed for the act stage, then, at least one action of each intention will be executed.

infrastructure: Centralised(pool,4,1,1,9999)

Finally, in the example below, the parameter [NUMBER-REASONING-CYCLES] is used. A thread pool with 4 threads is created, the sense and deliberate stages are configured to execute just once, while in the first case, the act stage executes at most 5 times, and in the second case, at least one action of each intention will be executed. In both cases, the sense-deliberate-act sequence will be repeated 10 times.

infrastructure: Centralised(pool,4,1,1,5,10)
infrastructure: Centralised(pool,4,1,1,9999,10)

A further configuration for pools is to execute only one stage every time that a thread selects an agent. Thus, the thread, for example, will execute the sense stage and put the agent back to the queue, then, the next time that this agent is selected, the thread will execute the deliberate stage, and finally the act stage.

In this case, the algorithm presented previously is executed like this:

switch (stage)
  case SENSE:
    loop do <NUMBER-CYCLES-SENSE> times:
      sense();
    stage = DELIBERATE;
  case DELIBERATE:
    loop do <NUMBER-CYCLES-DELIBERATE> times:
      deliberate();
    stage = ACT;
  case ACT:
    loop do <NUMBER-CYCLES-ACT> times:
      act();
    stage = SENSE;

The parameters are almost the same as before, however, the first parameter must be defined as synch_scheduled and [NUMBER-REASONING-CYCLES] is not a parameter for this configuration. Thus, the examples aforementioned could be written exemplified below.

Using 4 threads, each stage will be executed once:

infrastructure: Centralised(synch_scheduled,4)

Each stage is executed at most 5 times:

infrastructure: Centralised(synch_scheduled,4,5)

The sense and deliberate stages are executed once, while the act stage is executed at most 5 times:

infrastructure: Centralised(synch_scheduled,4,1,1,5)

The sense and deliberate stages are executed once, and at least one action of each intention will be executed in the act stage:

infrastructure: Centralised(synch_scheduled,4,1,1,9999)

Asynchronous Reasoning Cycle

The asynchronous configuration can be configured to use a single thread pool to execute all the stages or to use one dedicated thread pool to execute each stage.

In the case of asynchronous execution, the tasks in the pool are the execution of a stage. The algorithm is the same independent of the number of threads or thread pools. Thus, each thread executes the stage according to its tasks, like the algorithm below.

switch (task.stage)
  case SENSE:
    loop do <NUMBER-CYCLES-SENSE> times:
      sense();
  case DELIBERATE:
    loop do <NUMBER-CYCLES-DELIBERATE> times:
      deliberate();
  case ACT:
    loop do <NUMBER-CYCLES-ACT> times:
      act();

The parameters to use a single thread pool are presented below:

infrastructure: Centralised(asynch_shared, <NUMBER-THREADS>,
    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>)

As in the pool case, the keyword asynch_shared makes the execution platform to create a thread pool with <NUMBER-THREADS> threads.

In the example below, a thread pool with 4 threads is created and each stage will be executed just once.

infrastructure: Centralised(asynch_shared,4)

In the example below, a thread pool with 4 threads is created, the sense and deliberate stages are configured to execute at most 15 times, and the act stage will be executed at most 20 times.

infrastructure: Centralised(asynch_shared,4,15,15,20)

In another configuration, each stage can be executed by a different thread pool. The parameters for this configuration are presented below.

infrastructure: Centralised(asynch,
    <NUMBER-THREADS-SENSE>, <NUMBER-THREADS-DELIBERATE>, <NUMBER-THREADS-ACT>)

or

infrastructure: Centralised(asynch,
    <NUMBER-THREADS-SENSE>, <NUMBER-THREADS-DELIBERATE>, <NUMBER-THREADS-ACT>,
    <NUMBER-CYCLES-SENSE>, <NUMBER-CYCLES-DELIBERATE>, <NUMBER-CYCLES-ACT>)

The keyword asynch makes the execution platform to create three thread pools, one for each stage. <NUMBER-THREADS-SENSE> is the number of threads for the thread pool to execute the sense stage. <NUMBER-THREADS-DELIBERATE> is the number of threads for the thread pool to execute the deliberate stage. <NUMBER-THREADS-ACT> is the number of threads for the thread pool to execute the act stage.

In the example below, three thread pools with 4 threads each are created:

infrastructure: Centralised(asynch,4,4,4)

In the example below, three thread pools with 4 threads each are created, the sense and deliberate stages are configured to execute at most 15 times, and the act stage will be executed at most 20 times.

infrastructure: Centralised(asynch,4,4,4,15,15,20)

Individual Agents

Besides the global configuration for the MAS. Jason allows to configure the number of cycles for each agent individually, allowing to define a kind of priority by giving more CPU for certain agents than others. The parameters for the agents are presented by means of the two examples below.

The agent ana has the number of cycles for the sense and deliberate stages as 2, while the number of cycles for the act stage is 10:

ana [cycles_sense = 2, cycles_deliberate = 2, cycles_act = 10];

The agent bob has the number of cycles for the sequence sense-deliberate-act as 10:

bob [cycles = 10];
  1. Alex Muscar, Costin Badica. Monadic Foundations for Promises in Jason. ITC, v. 43, n. 1, p. 65–72, 2014. DOI: 10.5755/j01.itc.43.1.4586

  2. Alex Muscar. Agents for the 21st century: the blueprint agent programming language. In: Proc. of the 1st AAMAS Workshop on Engineering MultiAgent Systems, 2013. p. 49–64.

  3. Maicon R. Zatelli, Alessandro Ricci, Jomi F. Hübner. A Concurrent Architecture for Agent Reasoning Cycle Execution in Jason. In: 13th European Conference on Multi-Agent Systems (EUMAS), 2016, Athens. Multi-Agent Systems and Agreement Technologies, 2016. v. 9571. p. 425-440. DOI: 10.1007/978-3-319-33509-4_33

  4. Maicon R. Zatelli, Alessandro Ricci, Jomi F. Hübner. Evaluating Different Concurrency Configurations for Executing Multi-Agent Systems. In: 3rd International Workshop on Engineering Multi-agent Systems (EMAS@AAMAS), 2015, Istanbul. Engineering Multi-agent Systems, 2015. v. 9318. p. 212-230. DOI: 10.1007/978-3-319-26184-3_12

  5. Pascual Pérez-Carro, Francisco Grimaldo, Miguel Lozano, Juan M. Orduña. Characterization of the Jason Multiagent Platform on Multicore Processors. Scientific Programming 22(1). p 21-35, 2014. DOI: 10.3233/SPR-130375

  6. Victor Fernández-Bauset, Francisco Grimaldo, Miguel Lozano, Juan M. Orduña. Tuning Java to Run Interactive Multiagent Simulations over Jason. In: LI, J. (Ed.). Australasian Conference on Artificial Intelligence, 2010. (Lecture Notes in Computer Science, v. 6464), p. 354–363. DOI: 10.1007/978-3-642-17432-2_36

  7. Victor Fernández, Francisco Grimaldo, Miguel Lozano, Juan M. Orduña. Evaluating Jason for Distributed Crowd Simulations. In: FILIPE, J.; FRED, A. L. N.; SHARP, B. (Ed.). ICAART (2). [S.l.]: INSTICC Press, 2010. p. 206–211. ISBN 978-989-674-022-1.