main.rs (3526B)
1 //! Actors are easier to conceptualize. 2 //! Actors contain their state. If you want to see all interactions with 3 //! that state, you look in the actor code. 4 //! However, with mutex codebases, we do not know where all the 5 //! interactions with the states are, which could make it harder 6 //! to maintain. 7 8 use std::sync::Arc; 9 10 use actor_model::{ 11 basic_actor::{Message, RespMessage, basic_actor, resp_actor}, 12 mutex_replacement::actor_replacement, 13 }; 14 use tokio::sync::{Mutex, mpsc::channel, oneshot}; 15 16 #[tokio::main] 17 async fn main() { 18 // 1. Basic actor without responder 19 // let (tx, rx) = channel::<Message>(100); 20 21 // let _actor_handle = tokio::spawn(basic_actor(rx)); 22 23 // for i in 0..10 { 24 // let msg = Message { value: i }; 25 // tx.send(msg).await.unwrap(); 26 // } 27 28 // 2. Basic actor with responder 29 // if we want to send a message to our responding actor, we need to 30 // construct a onshot channel. 31 let (tx, rx) = channel::<RespMessage>(100); 32 33 let _resp_actor_handle = tokio::spawn(async { 34 resp_actor(rx).await; 35 }); 36 37 for i in 0..10 { 38 // We use a oneshot channel because we need the response to be 39 // sent only once and then close; after that the client code 40 // can go about doing other things. 41 let (resp_tx, resp_rx) = oneshot::channel::<i64>(); 42 43 let msg = RespMessage { 44 value: i, 45 responder: resp_tx, 46 }; 47 tx.send(msg).await.unwrap(); 48 // do something else after sending the message and waiting 49 // for the response, without needing to spawn async tasks. 50 // this flexibility of choosing when to wait for the result 51 // of the message comes for free withg actors. 52 println!("Response: {}", resp_rx.await.unwrap()); 53 } 54 55 // 3.1 Actor replacement using mutex: Elapsed: 602.618µs 56 // let state = Arc::new(Mutex::new(0)); 57 // let mut handles = Vec::new(); 58 59 // let now = tokio::time::Instant::now(); 60 61 // for i in 0..100 { 62 // let state_ref = state.clone(); 63 // let future = async move { 64 // let handle = tokio::spawn(async move { actor_replacement(state_ref, i).await }); 65 66 // let _ = handle.await.unwrap(); 67 // }; 68 // handles.push(tokio::spawn(future)); 69 // } 70 // for handle in handles { 71 // let _ = handle.await.unwrap(); 72 // } 73 // println!("Elapsed: {:?}", now.elapsed()); 74 75 // 3.2 Actor approach: Elapsed: 313.017µs 76 // 77 // Generally, passing messages through channels can scale better than 78 // mutexes in concurrent environments, because the senders do not 79 // have to wait for other tasks to finish what they are doing. 80 // let (tx, rx) = channel::<RespMessage>(100); 81 // let _resp_actor_handle = tokio::spawn(async { 82 // resp_actor(rx).await; 83 // }); 84 85 // let mut handles = Vec::new(); 86 87 // let now = tokio::time::Instant::now(); 88 // for i in 0..100 { 89 // let tx_ref = tx.clone(); 90 91 // let future = async move { 92 // let (resp_tx, resp_rx) = oneshot::channel::<i64>(); 93 // let msg = RespMessage { 94 // value: i, 95 // responder: resp_tx, 96 // }; 97 // tx_ref.send(msg).await.unwrap(); 98 // let _ = resp_rx.await.unwrap(); 99 // }; 100 // handles.push(tokio::spawn(future)); 101 // } 102 // for handle in handles { 103 // handle.await.unwrap(); 104 // } 105 // println!("Elapsed: {:?}", now.elapsed()); 106 }