Rust Tokio Async performance

739 Views Asked by At

I'm looking to create a high throughput, low-latency marketplace using Rust. I was doing some performance testing on the serialization and found that it was pretty slow (0.05ms). After some investigation I found that using Tokio and Async with Rust slowed down code that is just part of a function that has an await in it.

I have two main questions:

  1. Is there any information on why this might be?
  2. How can I trace the code to see exactly what's being run so I can find out what's going on (I've done profiling already using perf and hotspot).

Below is the code that I've created that shows the performance difference. It runs a "with_await" and a "without_await" function in two configurations, once just by awaiting and once as a spawned future, and both show similar performance. (These times are in ms)

with_await 0.04643426799999998
without_await 0.009190136999999998
without_await 0.009858687000000007
with_await 0.050352950999999944
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use serde_json::Value;
use tokio::time::sleep;

static JSON_BLOB: &str = "{\"arg\":{\"channel\":\"basket_orders\",\"order_name\":\"socks\"},\"data\":[{\"prices\":[[\"15.15\",\"22.22\",\"12.5\",\"22.0\"]],\"amounts\":[[\"10\",\"20\",\"10\",\"15\"]],\"ts\":\"1680917016349\"}]}";

pub fn utcnow() -> Duration {
    SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
}

async fn with_await() {
    let mut diff_sum = 0_f64;
    for count in 1..=1000 {
        sleep(Duration::from_millis(1)).await;
        let blah: &str = JSON_BLOB.as_ref();
        let received_time = utcnow().as_nanos();
        let value: Value = serde_json::from_str(blah).unwrap();
        let millis_diff = (utcnow().as_nanos() - received_time) as f64 / 1_000_000.0;
        diff_sum += millis_diff;
    }
    println!("with_await {}", diff_sum / 1000_f64);
}

async fn without_await() {
    let mut diff_sum = 0_f64;
    for count in 1..=1000 {
        let blah: &str = JSON_BLOB.as_ref();
        let received_time = utcnow().as_nanos();
        let value: Value = serde_json::from_str(blah).unwrap();
        let millis_diff = (utcnow().as_nanos() - received_time) as f64 / 1_000_000.0;
        diff_sum += millis_diff;
    }
    println!("without_await {}", diff_sum / 1000_f64);
}

#[tokio::main]
async fn main() {
    with_await().await;
    without_await().await;

    let mut handles = vec![];
    handles.push(tokio::spawn(with_await()));
    handles.push(tokio::spawn(without_await()));
    futures::future::join_all(handles).await;
}

Dependencies are:

[dependencies]
futures = "0.3.28"
serde = "1.0.159"
serde_json = "1.0.95"
tokio = { version = "1.27.0", features = ["full"] }
0

There are 0 best solutions below