commit 595647342c5cfb08cd89c1f3a87ef9018bdbe1c6
parent 84519c9468c78e025bc153442114142efd553788
Author: ling0x <ling0x@users.noreply.github.com>
Date: Tue, 4 Aug 2026 19:57:01 +0100
actor model
Diffstat:
6 files changed, 364 insertions(+), 0 deletions(-)
diff --git a/actor_model/Cargo.lock b/actor_model/Cargo.lock
@@ -0,0 +1,218 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "actor_model"
+version = "0.1.0"
+dependencies = [
+ "tokio",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
+
+[[package]]
+name = "bytes"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.189"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "mio"
+version = "1.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.107"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
+dependencies = [
+ "errno",
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+
+[[package]]
+name = "socket2"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "syn"
+version = "3.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tokio"
+version = "1.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "parking_lot",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
diff --git a/actor_model/Cargo.toml b/actor_model/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "actor_model"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+tokio = { version = "1.53.1", features = ["full"] }
diff --git a/actor_model/src/basic_actor.rs b/actor_model/src/basic_actor.rs
@@ -0,0 +1,31 @@
+use tokio::sync::{mpsc::Receiver, oneshot};
+
+pub struct Message {
+ pub value: i64,
+}
+
+pub async fn basic_actor(mut rx: Receiver<Message>) {
+ let mut state = 0;
+
+ while let Some(msg) = rx.recv().await {
+ state += msg.value;
+ println!("Received: {}", msg.value);
+ println!("State: {}", state);
+ }
+}
+
+pub struct RespMessage {
+ pub value: i64,
+ pub responder: oneshot::Sender<i64>,
+}
+
+pub async fn resp_actor(mut rx: Receiver<RespMessage>) {
+ let mut state = 0;
+
+ while let Some(msg) = rx.recv().await {
+ state += msg.value;
+ if msg.responder.send(state).is_err() {
+ eprintln!("Failed to send response");
+ }
+ }
+}
diff --git a/actor_model/src/lib.rs b/actor_model/src/lib.rs
@@ -0,0 +1,2 @@
+pub mod basic_actor;
+pub mod mutex_replacement;
diff --git a/actor_model/src/main.rs b/actor_model/src/main.rs
@@ -0,0 +1,96 @@
+use std::sync::Arc;
+
+use actor_model::{
+ basic_actor::{Message, RespMessage, basic_actor, resp_actor},
+ mutex_replacement::actor_replacement,
+};
+use tokio::sync::{Mutex, mpsc::channel, oneshot};
+
+#[tokio::main]
+async fn main() {
+ // 1. Basic actor without responder
+ // let (tx, rx) = channel::<Message>(100);
+
+ // let _actor_handle = tokio::spawn(basic_actor(rx));
+
+ // for i in 0..10 {
+ // let msg = Message { value: i };
+ // tx.send(msg).await.unwrap();
+ // }
+
+ // 2. Basic actor with responder
+ // if we want to send a message to our responding actor, we need to
+ // construct a onshot channel.
+ // let (tx, rx) = channel::<RespMessage>(100);
+
+ // let _resp_actor_handle = tokio::spawn(async {
+ // resp_actor(rx).await;
+ // });
+
+ // for i in 0..10 {
+ // // We use a oneshot channel because we need the response to be
+ // // sent only once and then close; after that the client code
+ // // can go about doing other things.
+ // let (resp_tx, resp_rx) = oneshot::channel::<i64>();
+
+ // let msg = RespMessage {
+ // value: i,
+ // responder: resp_tx,
+ // };
+
+ // tx.send(msg).await.unwrap();
+ // println!("Response: {}", resp_rx.await.unwrap());
+ // }
+
+ // 3.1 Actor replacement using mutex: Elapsed: 602.618µs
+ // let state = Arc::new(Mutex::new(0));
+ // let mut handles = Vec::new();
+
+ // let now = tokio::time::Instant::now();
+
+ // for i in 0..100 {
+ // let state_ref = state.clone();
+ // let future = async move {
+ // let handle = tokio::spawn(async move { actor_replacement(state_ref, i).await });
+
+ // let _ = handle.await.unwrap();
+ // };
+ // handles.push(tokio::spawn(future));
+ // }
+ // for handle in handles {
+ // let _ = handle.await.unwrap();
+ // }
+ // println!("Elapsed: {:?}", now.elapsed());
+
+ // 3.2 Actor approach: Elapsed: 313.017µs
+ //
+ // Generally, passing messages through channels can scale better than
+ // mutexes in concurrent environments, because the senders do not
+ // have to wait for other tasks to finish what they are doing.
+ let (tx, rx) = channel::<RespMessage>(100);
+ let _resp_actor_handle = tokio::spawn(async {
+ resp_actor(rx).await;
+ });
+
+ let mut handles = Vec::new();
+
+ let now = tokio::time::Instant::now();
+ for i in 0..100 {
+ let tx_ref = tx.clone();
+
+ let future = async move {
+ let (resp_tx, resp_rx) = oneshot::channel::<i64>();
+ let msg = RespMessage {
+ value: i,
+ responder: resp_tx,
+ };
+ tx_ref.send(msg).await.unwrap();
+ let _ = resp_rx.await.unwrap();
+ };
+ handles.push(tokio::spawn(future));
+ }
+ for handle in handles {
+ handle.await.unwrap();
+ }
+ println!("Elapsed: {:?}", now.elapsed());
+}
diff --git a/actor_model/src/mutex_replacement.rs b/actor_model/src/mutex_replacement.rs
@@ -0,0 +1,10 @@
+use std::sync::Arc;
+
+use tokio::sync::Mutex;
+
+// Experimenting with an actor replacement by using a simple mutex
+pub async fn actor_replacement(state: Arc<Mutex<i64>>, value: i64) -> i64 {
+ let mut state = state.lock().await;
+ *state += value;
+ *state
+}