0

我使用 tokio 来监听 UDP 套接字。我发送/接收bincode编码结构并使用serde.

但是我应该如何处理Arc<tokio::sync::RwLock<T>>字段的序列化?(我知道 serde 支持标准库同步RwLock,但我需要异步)。

数据经常通过网络更改和传输(根据设计),因此每次我需要发送内容时等待多个读取锁可能不是一个好主意。

考虑到 serde 是同步的,我必须为每个RwLock字段生成阻塞 tokio 任务。(每个领域都有RwLock自己的领域)。所以这会变得非常慢。

处理这个的生锈方法是什么?

例子:

use serde::{Deserialize, Serialize};
use tokio::sync::RwLock;

#[derive(Serialize, Deserialize)]
struct Player {
  // In order to serialize Player i'd have to one by one acquire lock for `meta` and then `stats`, and then some other potential fields.
  pub id: u64,
  pub meta: Arc<RwLock<Metadata>>,
  pub stats: Arc<RwLock<Metadata>>,  
  pub someOtherField1: Arc<RwLock<...>>,
  pub someOtherField2: Arc<RwLock<...>>,
  pub someOtherField3: Arc<RwLock<...>>,
}

4

1 回答 1

2

数据经常通过网络更改和传输(根据设计),因此每次我需要发送内容时等待多个读取锁可能不是一个好主意。

忘掉性能吧——这不会是你在任何类型的游戏网络中的瓶颈(这确实是你想要做的)。

唯一正确的方法是在序列化数据之前在每个字段上获取一个读锁,然后将它们全部序列化。如果你不这样做,你最终会得到从逻辑上不存在的不一致状态。玩家可能还活着但生命值为 0,或者在游戏中断开连接。

这可能会导致死锁!这是您开始共享数据时选择的难度。有一个非常好的经验法则可以防止死锁,如果你虔诚地坚持它,你必须在整个代码中这样做:任何获取多个锁的例程都必须以相同的顺序获取它们。如果需要一个新锁,但我们已经有其他锁在顺序后面,我们必须先释放所有锁,然后再以正确的顺序再次获取它们。

坚持上述原则的最简单方法是只为玩家设置一个锁。

于 2021-11-10T14:19:13.883 回答