Hi Everyone.
I prototype another scenario
in that i not used any wrapper over rust + tokio !!
just used internal features
scenario 1.
in this scenario i used message passing and a calculate operation
first spawn some worker ( number == my cpu core)
then sending request to each worker and await for result of each worker and it do simple sum over N counter and then response Result::Ok in rust in elixir :ok
Rust Client
use chrono::PreciseTime;
mod server;
use server::server::{ start, MReq, MResp, Request};
use tokio::{sync::oneshot::{self, Receiver}};
#[tokio::main]
async fn main() {
let server1 = start().await;
let server2 = start().await;
let server3 = start().await;
let start = PreciseTime::now();
// ===================================================
for n in 0..1000 {
let (recv_resp1, req1) = request_factory(n);
let (recv_resp2, req2) = request_factory(n);
let (recv_resp3, req3) = request_factory(n);
let _ = server1.send(req1).await;
let _ = recv_resp1.await;
let _ = server2.send(req2).await;
let _ = recv_resp2.await;
let _ = server3.send(req3).await;
let _ = recv_resp3.await;
}
// ===================================================
let end = PreciseTime::now();
let tm = start.to(end).num_microseconds().unwrap();
println!("==> {} ns (microseconds)", tm)
}
fn request_factory(n: i32) -> (Receiver<MResp>, Request<MReq, MResp>) {
let (resp, recv) = oneshot::channel::<MResp>();
let req = Request::<MReq, MResp> {
msg: MReq::Event(n),
resp
};
(recv, req)
}
Rust Server
pub mod server {
use tokio::sync::mpsc::{self};
use tokio::sync::oneshot::{self};
pub struct Request<MReq, MResp> {
pub msg : MReq,
pub resp: oneshot::Sender<MResp>
}
pub enum MReq {
Event(i32)
}
pub enum MResp {
Event(Result<(), ()>)
}
pub async fn start() -> mpsc::Sender<Request<MReq, MResp>> {
let (client, mut server) =
mpsc::channel::<Request<MReq, MResp>>(16);
tokio::spawn(async move {
while let Some(req) = server.recv().await {
let MReq::Event(n) = req.msg;
{
let mut temp = 1;
for num in 1..n {
temp += num;
}
}
let _ = req.resp.send(MResp::Event(Ok(())));
}
});
client
}
}
Elixir Server
defmodule Todo.Server do
use GenServer
def start(args) do
GenServer.start(__MODULE__, args)
end
def init(init_arg) do
{:ok, init_arg}
end
# ========================================
def handle_call({:event, n}, _from, state) do
execute(n, 1)
{:reply, :ok, state}
end
def execute(1, _) do
:ok
end
def execute(num, temp) do
execute(num-1, temp + num)
end
end
Elixir Client
defmodule Todo.Client do
def start(n) do
{:ok, server1} = Todo.Server.start([])
{:ok, server2} = Todo.Server.start([])
{:ok, server3} = Todo.Server.start([])
{tm, _} = :timer.tc(fn ->
Todo.Client.loop({n, server1, server2, server3})
end)
IO.write("#{tm} ns")
end
def loop({0, _, _, _}) do
:done
end
def loop({n, server1, server2, server3}) do
GenServer.call(server1, {:event, n})
GenServer.call(server2, {:event, n})
GenServer.call(server3, {:event, n})
loop({n-1, server1, server2, server3})
end
end
above i said N sum operation N is iteration in below
Result is Amazing :
Scenario over 1,000 iteration
Rust+Tokio : 144,792 microseconds
Elixir/Beam : 23,393 microseconds
Scenario over 10,000 iteration
Rust+Tokio : 5,503,831 microseconds
Elixir/Beam : 812,285 microseconds
even with arithmetic operation beam was winner