【发布时间】:2021-06-02 17:35:17
【问题描述】:
我正在编写一个使用两个线程的模拟程序:一个用于实际模拟,另一个用于渲染。
模拟线程具有Entity 结构中的Vec,它使用每个tick。当渲染线程需要访问实体的Vec 以渲染它们时,就会出现我的问题,但是Entity 结构的某些字段没有实现Send 特征。但是,这些字段实际上并不用于渲染。
我想到的唯一解决方案是将每个实体拆分为两个结构:一个包含内部“不可发送”字段,另一个包含渲染所需的字段。然后我可以使用两个单独的Vecs 并将“可发送”的一个包装在Mutex 中并与渲染线程共享。然而,这意味着每个实体将有两个部分,并且每个结构都必须存储另一部分的索引以将它们联系在一起,但是当实体被创建和删除很多时,管理起来感觉非常头疼。
在 Rust 中有标准的方法吗?对于很多程序来说,这感觉是一个相当普遍的要求,但我找不到一个简单的方法来做到这一点。
【问题讨论】:
-
不实现
Send的Rust 对象实际上非常罕见——只有Rc和RefCell会浮现在脑海中,原始指针也是如此。您的字段有哪些非发送类型? -
如果您的字段必须保持非
Send,一种不涉及拆分实体的可能解决方案是使用(命名不当)fragilecrate。然后您可以将非Send字段包装在Fragile<T>中,这将阻止它们在原始线程之外使用(使用运行时检查),但允许将整个对象传递给其他线程,并允许您可以使用实际上是Send的字段。 -
非
Send类型来自 pyo3 crate,所以它们是不可避免的 - 我会研究一下脆弱的 crate,它看起来很有希望 -
希望对您有所帮助,祝您好运。出于好奇,哪些 pyo3 类型是非发送的?通过查看 pyo3 文档,我了解到它围绕 Python 对象的包装器是
Send和Sync,但使用它们需要提供PythonGIL 令牌作为获得 GIL 的证明。例如。Py<T>是Send和Sync。 -
我使用的类型
PyAny没有实现Send或Sync。我现在已经将这个值包装在Py类型中,留下一个Py<PyAny>,它实际上可以在线程之间发送!我仍然会在答案中使用 ECS 设计,因为它会使我的程序更高效
标签: multithreading rust