Concurrency in Ballerina is enabled by strands, which are lightweight threads.
Ballerina's concurrency model supports both threads and coroutines and has been designed to have a close correspondence with sequence diagrams.
A Ballerina program is executed on one or more threads. A thread can consist of one or more strands, which are language-managed, logical threads of control. Only one strand of a particular thread can run at a time. The strands belonging to a single thread are cooperatively multitasked. Therefore, strands of a single thread behave as coroutines relative to each other.
Strands enable cooperative multitasking by "yielding". The runtime scheduler may switch the execution of a strand only when it yields via a
wait action, a worker receive action, a library function resulting in a blocking call, etc.
A strand is created due to the execution of either a named worker declaration or
Concurrent operations in a function can be defined by multiple named workers. A function has a default worker and may additionally contain named workers. A worker executes concurrently with the other workers (function worker and named workers) in the function.
Worker message passing (via Ballerina’s
send (->) and
receive (<-) actions) is used for communication between workers. The compiler also explicitly verifies that the
receive actions are in a consistent state to avoid any deadlock scenarios at runtime.
@strand annotation can be used on a named worker or start action to make the corresponding strand run on a separate thread.
Concurrency in Ballerina works well with sequence diagrams. A function can be viewed as a sequence diagram. Each worker is represented by a separate lifeline (vertical line).
Immutability in the type system can be leveraged to write reliable concurrent programs. Immutability in Ballerina is deep guaranteeing that an immutable structure will always have only immutable values. Therefore, an immutable value can be safely accessed concurrently without using a lock statement.