Use rust development demo to test, cpu usage is as high as 28%, is it normal

Start the rust and golang two versions of the web server (both have http and grpc services), the rust version of the cpu usage is so high (see figure), jumping around 28%, the rust version of the code is as follows:

use axum::{
    routing::{get, post},
    Router,
};
use logic::pb::{
    logic_server::{Logic, LogicServer},
    ConnReply, ConnRequest,
};
use tokio::{net::TcpListener, spawn};
use tonic::{transport::Server, Request, Response, Status};

#[tokio::main]
async fn main() {
    let _ = spawn(async {
        let _ = http_srv().await;
    });

    let _ = spawn(async {
        let _ = grpc_srv().await;
    });
    loop {}
}

async fn http_srv() -> Result<(), axum::Error> {
    println!("http server");

    let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();

    let router = Router::new()
        .route("/", get(root))
        .route("/admin", post(admin_handler));

    axum::serve(listener, router).await.unwrap();

    Ok(())
}

async fn grpc_srv() -> Result<(), tonic::transport::Error> {
    println!("grpc server");

    let addr = "[::1]:50052".parse().unwrap();
    let greeter = LogicSrv::default();

    Server::builder()
        .add_service(LogicServer::new(greeter))
        .serve(addr)
        .await?;

    Ok(())
}

async fn root() -> &'static str {
    "home page"
}

async fn admin_handler() -> &'static str {
    "admin page"
}

#[derive(Debug, Default)]
pub struct LogicSrv;

#[tonic::async_trait]
impl Logic for LogicSrv {
    async fn conn(&self, request: Request<ConnRequest>) -> Result<Response<ConnReply>, Status> {
        println!("Got a request: {:#?}", request);

        let reply = ConnReply {
            message: format!("Hello {}", request.into_inner().name),
        };

        Ok(Response::new(reply))
    }
}

The proto file code for grpc is as follows:
syntax = "proto3";
package logic;
service Logic { rpc Conn(ConnRequest) returns (ConnReply); }
message ConnRequest { string name = 1; }
message ConnReply { string message = 1; }

The startup binaries have been packaged using 'cargo build-r'

Why is that? Does it need to be optimized

This literally is a spin loop. Honestly I'm impressed that it only consumes ~28% of CPU time.

If you want to wait for the spawned task .join().await the join handles returned from those spawn() calls, in however order but after all the tasks are spawned. If you want to pause indefinitely without busy loop, that's std::future::pending().await.

Also mandatory checklist, have you run it with --release flag? Seems it's checked

2 Likes

OP probably has a quad core system. Windows shows cpu time as percentage of the combined cpu time available on all cores. So fully loading one core on a quad core system will show up as 25% cpu usage.

Yes, I'm surprised it even runs at all. Surely if tokio was single threaded, did not farm tasks out to threads, that spin loop would hang up the run time and nothing could make progress.

#[tokio::main] defaults to multi-thread, in which not only are there more threads, but main() doesn't participate in running any spawned tasks, only whatever code is not spawned.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.