pub struct Process<M, S = Bincode> { /* private fields */ }
Expand description
Processes are isolated units of compute.
In lunatic, all code runs inside processes. Processes run concurrently and communicate via message passing.
Lunatic’s processes should not be confused with operating system processes. Processes in lunatic are extremely lightweight in terms of memory and CPU (even compared to threads as used in many other programming languages). Because of this, it is not uncommon to have tens or even hundreds of thousands of processes running simultaneously.
The Process
type allows us to spawn new processes from rust functions. There are two kinds
of processes:
- Mailbox based processes
- Protocol based processes
They are differentiated by the second argument of the entry function.
Mailbox based processes
A mailbox process takes a Mailbox
that can only receive messages of one
type.
Example
let child = Process::spawn(1, |capture, mailbox: Mailbox<i32>| {
assert_eq!(capture, 1);
assert_eq!(mailbox.receive(), 2);
});
child.send(2);
Processes don’t share any memory and messages sent between them need to be serialized. By
default, the Bincode
serializer is used, but other serializers that implement the
Serializer
trait can be used instead. The serializer just needs to be added to the
Mailbox
type (e.g. Mailbox<i32, MessagePack>
).
Processes can also be linked together using the spawn_link
function.
This means that if one of them fails (panics) the other will be killed too. It is always
recommended to spawn linked processes when they depend on each other. That way we can avoid
one process forever waiting on a message from another process that doesn’t exist anymore.
Protocol based processes
A protocol process takes a Protocol
that can define a sequence
of messages that will be exchanged between two processes. This is also known as a session type.
The child will get a reference to the protocol and the parent will get a reference to the
opposite protocol.
Example
type AddProtocol = Recv<i32, Recv<i32, Send<i32, End>>>;
let child = Process::spawn(1, |capture: i32, protocol: Protocol<AddProtocol>| {
assert_eq!(capture, 1);
let (protocol, a) = protocol.receive();
let (protocol, b) = protocol.receive();
let _ = protocol.send(capture + a + b);
});
let child = child.send(2);
let child = child.send(2);
let (_, result) = child.receive();
assert_eq!(result, 5);
The rust type system guarantees that the all messages are sent in the correct order and are of correct type. Code that doesn’t follow the protocol would not compile.
Same as the mailbox, the protocol based process can choose another serializer (e.g.
Protocol<AddProtocol, MessagePack>
).
If a protocol based process is dropped before the End
state is reached, the drop will panic.
Implementations
sourceimpl<M, S> Process<M, S>
impl<M, S> Process<M, S>
sourcepub fn spawn<C, T>(capture: C, entry: fn(_: C, _: T)) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
T: NoLink,
pub fn spawn<C, T>(capture: C, entry: fn(_: C, _: T)) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
T: NoLink,
Spawn a process.
sourcepub fn spawn_link<C, T>(capture: C, entry: fn(_: C, _: T)) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
pub fn spawn_link<C, T>(capture: C, entry: fn(_: C, _: T)) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
Spawn a linked process.
sourcepub fn spawn_link_tag<C, T>(
capture: C,
tag: Tag,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
pub fn spawn_link_tag<C, T>(
capture: C,
tag: Tag,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
Spawn a linked process with a tag.
Allows the caller to provide a tag for the link.
sourcepub fn spawn_config<C, T>(
config: &ProcessConfig,
capture: C,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
T: NoLink,
pub fn spawn_config<C, T>(
config: &ProcessConfig,
capture: C,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
T: NoLink,
Spawn a process with a custom configuration.
sourcepub fn spawn_link_config<C, T>(
config: &ProcessConfig,
capture: C,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
pub fn spawn_link_config<C, T>(
config: &ProcessConfig,
capture: C,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
Spawn a linked process with a custom configuration.
sourcepub fn spawn_link_config_tag<C, T>(
config: &ProcessConfig,
capture: C,
tag: Tag,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
pub fn spawn_link_config_tag<C, T>(
config: &ProcessConfig,
capture: C,
tag: Tag,
entry: fn(_: C, _: T)
) -> T::Process where
S: Serializer<C> + Serializer<ProtocolCapture<C>>,
T: IntoProcess<M, S>,
Spawn a linked process with a custom configuration & provide tag for linking.
Trait Implementations
sourceimpl<'de, M, S> Deserialize<'de> for Process<M, S>
impl<'de, M, S> Deserialize<'de> for Process<M, S>
sourcefn deserialize<D>(deserializer: D) -> Result<Process<M, S>, D::Error> where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Process<M, S>, D::Error> where
D: Deserializer<'de>,
Deserialize this value from the given Serde deserializer. Read more
Auto Trait Implementations
impl<M, S = Bincode> !RefUnwindSafe for Process<M, S>
impl<M, S> Send for Process<M, S> where
M: Send,
S: Send,
impl<M, S = Bincode> !Sync for Process<M, S>
impl<M, S> Unpin for Process<M, S> where
M: Unpin,
S: Unpin,
impl<M, S> UnwindSafe for Process<M, S> where
M: UnwindSafe,
S: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
sourceimpl<T> ToOwned for T where
T: Clone,
impl<T> ToOwned for T where
T: Clone,
type Owned = T
type Owned = T
The resulting type after obtaining ownership.
sourcefn clone_into(&self, target: &mut T)
fn clone_into(&self, target: &mut T)
toowned_clone_into
)Uses borrowed data to replace owned data, usually by cloning. Read more