exercises

Log | Files | Refs | README

commit 595647342c5cfb08cd89c1f3a87ef9018bdbe1c6
parent 84519c9468c78e025bc153442114142efd553788
Author: ling0x <ling0x@users.noreply.github.com>
Date:   Tue,  4 Aug 2026 19:57:01 +0100

actor model

Diffstat:
Aactor_model/Cargo.lock | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aactor_model/Cargo.toml | 7+++++++
Aactor_model/src/basic_actor.rs | 31+++++++++++++++++++++++++++++++
Aactor_model/src/lib.rs | 2++
Aactor_model/src/main.rs | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aactor_model/src/mutex_replacement.rs | 10++++++++++
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 +}