Skip to content

optimize network listener desc #39

Open

Description

@daheige

listeners: Mutex<HashMap<Arc<str>, BoxService>>,

listener 优化说明

  1. 不建议直接把字段改成 Arc<Mutex<HashMap<...>>> 作为性能优化。
  2. Arc 解决的是共享所有权,Mutex 解决的是互斥访问;加一层 Arc 不会减少锁竞争,仍然整张表只有一把锁。

如果 DhttpNetwork 已经通过 Arc<DhttpNetwork> 跨线程共享,那么现在的:

listeners: Mutex<HashMap<Arc<str>, BoxService>>,

已经能满足共享需求,通常不需要再写成:

// 一般不会带来性能提升
listeners: Arc<Mutex<HashMap<Arc<str>, BoxService>>>,

如果确实想优化并发,按目标选择

  1. 只增删查监听器,且存在明显锁竞争:用 DashMap 分片
use dashmap::DashMap;

pub struct DhttpNetwork {
    interfaces: interfaces::Interfaces,
    listeners: DashMap<Arc<str>, BoxService>,
    pool: h3x::Pool<ConnectionKey, QuicTransport, Error>,
}

初始化相应改为:

listeners: DashMap::new(),

增删查变成:

self.listeners.insert(name.clone(), service);

let exists = self.listeners.contains_key(name);

let removed = self.listeners.remove(name);

但需要注意:如果这里的 BoxService 是 tower::util::BoxService,它通常是 Send 但不一定是 Sync,直接放进 DashMap 可能遇到线程安全 trait 约束问题;而且调用 Service 往往需要 &mut self,不能简单理解为“换成分片表后调用就并发了”。

  1. 希望缩短整张表的持锁时间:表用 DashMap,每个监听器单独加锁
use dashmap::DashMap;
use std::sync::{Arc, Mutex};

type SharedListener = Arc<Mutex<BoxService>>;

pub struct DhttpNetwork {
    interfaces: interfaces::Interfaces,
    listeners: DashMap<Arc<str>, SharedListener>,
    pool: h3x::Pool<ConnectionKey, QuicTransport, Error>,
}

查找时只短暂持有 DashMap 的引用,克隆出 Arc 后立即释放表锁:

let listener = self
    .listeners
    .get(name)
    .map(|entry| Arc::clone(entry.value()));

随后只锁定目标监听器,不影响其他监听器的增删查。这个模式比 Arc<Mutex<HashMap<...>>> 更能细化锁粒度,但代价是每个服务多一次 Arc 分配和一层锁,是否更快需要压测验证。

异步场景的关键约束

无论用哪种方案,都不要在持有 std::sync::MutexGuard 或 DashMap 的 Ref/RefMut 时直接 .await:

let response_future = {
    let listener = listener.ok_or_else(|| /* listener not found */)?;
    let mut service = listener.lock().unwrap();

    // 根据实际 Service 流程,这里可能还需要先 poll_ready
    service.call(request)
}; // 在这里释放服务锁

let response = response_future.await?;

如果确实必须跨 .await 持锁,才考虑 tokio::sync::Mutex,但它解决的是异步持锁问题,不是自动带来性能提升。

结论:如果这里的设计,仅为“跨线程操作”不必加内层 Arc;为降低 listeners 锁竞争,优先考虑 DashMap。若调用监听器时不能持有表的分片锁,则采用 DashMap<Arc<str>, Arc<Mutex<BoxService>>> 会更合适。Arc<str> 本身作为键跨线程共享没有问题,不需要再给它套 Mutex。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions