messages
is a runtime-agnostic actor library.
It is heavily inspired by actix
, a great actor framework.
This crate can be used with any runtime, whether it's popular or not.
However, for the biggest one (tokio
and async-std
) there is an optional
built-in support enabling more convenient interface (such as an automatic
actor spawning).
actix
is a great, thoughtful, polished, and optimized library. If it is possible
for you, you should consider it as the main option.
However, if any of statements below apply to your use case, messages
may be better:
actix-rt
does not have work stealing
and thus some threads may be underloaded in that case).But what about xactor
?
xactor
is another good library inspired by Actix. It initially was built for async-std
but
then gained tokio
support.
Nonetheless, this library is not runtime-agnostic. It supports async-std
and tokio
v1, but
is not (yet) compatible with another runtimes.
That being said, messages
initially serves different purpose: provide a way to implement
actor workflow without having to think about supported runtimes.
This library is async-first, meaning that everything is made with respect to asynchronous architecture.
While in some cases synchronous interfaces could've been more performant, it'd make the interface much
more bloated. If synchronous actor interface is preferred, consider using actix
, as it provides one.
TL;DR: This library provides performance that is better than in actix
(for asynchronous message handling;
based on the ring benchmark used by actix
itself) and is tied up to using futures
channels.
More details are presented in the BENCHES.md.
Note: messages
treats async
and multi-threaded context as its main environment,
thus it may be less suitable (or, more precisely, less efficient) for the partially
sync context. For instance, the sync version of the ring benchmark is by 80% faster than this library.
```rust use messages::prelude::*;
struct Example; // Most of the types can be an actor.
// While Actor
implementation can be customized, it is not required.
impl Actor for Example {}
// Message handler that calculated sum of two numbers.
impl Handler<(u8, u8)> for Example {
type Result = u16;
async fn handle(&mut self, (a, b): (u8, u8), context: &Context
// Notification handler that calculated just writes received number to stdout.
impl Notifiable
async fn main() {
let mut addr = Example.spawn();
let result = addr.send((22, 20)).await.unwrap();
asserteq!(result, 42);
addr.notify(42).await.unwrap();
addr.stop().await;
addr.waitfor_stop().await;
}
```
```rust use messages::prelude::*;
struct Ping;
impl Actor for Ping {}
impl Handler
async fn main() { let context = Context::new(); let mut addr = context.address(); let actor = Ping; // Could've been any other runtime. let mut taskhandle = tokio::spawn(context.run(actor)); let result = addr.send(42).await.unwrap(); asserteq!(result, 42); addr.stop().await; addr.waitforstop().await; task_handle.await.unwrap(); } ```
More examples can be found in the examples directory.
They are numbered and written in a manner so that the next example is always somewhat superior to the previous one. You can consider it to be a temporary alternative for a book (which is coming later).
List of currently provided examples:
actix
example.async-std
: Version of the Notify
example adapted for async-std
runtime.smol
: Example of using a runtime not supported out of the box. In that case, smol
.All kinds of contributions are really appreciated!
messages
library is licensed under the MIT License. See LICENSE for details.