0

我正在尝试为庞大的数据结构制作一个问答服务器。用户将 JSON 问题发送到服务器,服务器将使用庞大的数据结构来回答。

我试图通过hyper::server::Service为我的Oracle结构实现特征来做到这一点。

我有这样的事情:

use self::hyper::server::{Http, Service, Request, Response};
// ...other imports

struct Oracle { /* Tons of stuff */}

impl<'a> Service for &'a Oracle {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = Box<Future<Item = Self::Response, Error = Self::Error>>;

    fn call(&self, req: Request) -> Self::Future {
         match (req.method(), req.path()) {
            // could be lots of question types
            (&hyper::Method::Post, "/query") => {
                Box::new(req.body().concat2().map(|b| {
                    let query: Query = deserialize_req(&b.as_ref());
                    let ans = get_answer(&self, &query);
                    Response::new()
                        .with_header(ContentLength(ans.len() as u64))
                        .with_body(ans)
                }))
            },
            _ => {
                let response = Response::new()
                    .with_status(hyper::StatusCode::NotFound);
                Box::new(futures::future::ok(response))
            },
        }
    }
}

cannot infer an appropriate lifetime due to conflicting requirements当我尝试投入&self未来时,这会导致终身问题( )。

我的倾向是,这是解决这个问题的完全错误的方法,但我很难找出最好的方法来解决这个问题。

4

1 回答 1

2

请注意,这些 future 将是计算密集型的,在CPU 池上运行它们并避免在异步单线程 Tokio Core 堆栈上运行它们是有意义的。

&selfincall是对调用站点管理的内存的引用。调用站点可能会在调用之后立即释放该内存,或者在我们无法控制的其他时间,因此将引用保存在闭包中(“关闭引用”)以供以后使用是错误的。

为了以更好地共享内存的方式管理内存,您通常会使用引用计数指针。然后Oracle内存将由引用计数指针而不是调用站点拥有,允许您Oracle与闭包和线程自由共享。

如果要并行处理这些期货,则需要一个线程安全的引用计数指针,例如Arc.

要使用Arc,您可以将call转换为自由函数:

fn call(oracle: Arc<Oracle>, req: Request) -> OracleFuture

或者使用 trait 来实现callon 指针:

struct Oracle { /* Tons of stuff */}

type OraclePt = Arc<Oracle>;

trait OracleIf {
  fn call(&self, req: Request) -> Self::Future
}

impl OracleIf for OraclePt {
  fn call(&self, req: Request) -> Self::Future {
    ...
            let oracle: OraclePt = self.clone();
            Box::new(req.body().concat2().map(move |b| {  // Close over `oracle`.
                let query: Query = deserialize_req(&b.as_ref());
                let ans = get_answer(&*oracle, &query);
                Response::new()
                    .with_header(ContentLength(ans.len() as u64))
                    .with_body(ans)
            }))
  }
}

我们在这里关闭引用计数指针的副本。

如果您不喜欢使用引用计数指针的想法,那么另一种选择是使用“作用域线程池”,该线程池保证子线程在父线程之前终止,从而可以安全地Oracle与子线程共享引用。
如果不将计算包装在Future.

于 2018-01-10T02:45:00.887 回答