【问题标题】:Shared mutable state in HyperHyper 中的共享可变状态
【发布时间】:2018-10-24 16:39:08
【问题描述】:

我正在尝试在 Hyper Web 服务器中创建一个计数器,用于计算它收到的请求数。我正在使用Arc<Mutex<u64>> 来保持计数。但是,我无法找出move.clone() 的正确组合来满足闭包的类型。下面是一些可以编译的代码,但会在每次请求时重置计数器:

extern crate hyper;

use hyper::rt::Future;
use hyper::service::service_fn_ok;
use hyper::{Body, Response, Server};
use std::sync::{Arc, Mutex};

fn main() {
    let addr = "0.0.0.0:3000".parse().unwrap();
    // FIXME want to create the counter here, not below
    let server = Server::bind(&addr)
        .serve(|| {
            service_fn_ok(|_req| {
                let counter = Arc::new(Mutex::new(0));
                use_counter(counter)
            })
        })
        .map_err(|e| eprintln!("Error: {}", e));
    hyper::rt::run(server)
}

fn use_counter(counter: Arc<Mutex<u64>>) -> Response<Body> {
    let mut data = counter.lock().unwrap();
    *data += 1;
    Response::new(Body::from(format!("Counter: {}\n", data)))
}

【问题讨论】:

    标签: rust hyper rust-tokio


    【解决方案1】:

    事实证明我已经很接近了,查看其他一些示例帮助我意识到了问题所在。由于这里有两层闭包,我需要将counter 移动到外部闭包中,克隆它,然后将该克隆移动到内部闭包并再次克隆。也就是说:

    extern crate hyper; // 0.12.10
    
    use hyper::rt::Future;
    use hyper::service::service_fn_ok;
    use hyper::{Body, Response, Server};
    use std::sync::{Arc, Mutex};
    
    fn main() {
        let addr = "0.0.0.0:3000".parse().unwrap();
        let counter = Arc::new(Mutex::new(0));
        let server = Server::bind(&addr)
            .serve(move || {
                let counter = counter.clone();
                service_fn_ok(move |_req| use_counter(counter.clone()))
            })
            .map_err(|e| eprintln!("Error: {}", e));
        hyper::rt::run(server)
    }
    
    fn use_counter(counter: Arc<Mutex<u64>>) -> Response<Body> {
        let mut data = counter.lock().unwrap();
        *data += 1;
        Response::new(Body::from(format!("Counter: {}\n", data)))
    }
    

    2020 年 2 月更新这是使用 hyper 0.13 的版本:

    use hyper::{Body, Response, Server, Request};
    use std::sync::{Arc, Mutex};
    use hyper::service::{make_service_fn, service_fn};
    use std::convert::Infallible;
    
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
        let addr = "0.0.0.0:3000".parse()?;
        let counter = Arc::new(Mutex::new(0));
    
        let make_service = make_service_fn(move |_conn| {
            let counter = counter.clone();
            async move {
                Ok::<_, Infallible>(service_fn(move |_req: Request<Body>| {
                    let counter = counter.clone();
                    async move {
                        Ok::<_, Infallible>(use_counter(counter))
                    }
                }))
            }
        });
    
        Server::bind(&addr).serve(make_service).await?;
        Ok(())
    }
    
    fn use_counter(counter: Arc<Mutex<u64>>) -> Response<Body> {
        let mut data = counter.lock().unwrap();
        *data += 1;
        Response::new(Body::from(format!("Counter: {}\n", data)))
    }
    

    【讨论】:

    • 我也提供了 hyper 0.13 版本
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    相关资源
    最近更新 更多