不同的线程可以写入同一Vec的不同部分吗?

时间:2016-10-08 02:20:35

标签: rust

我有10个主题,长度为100的Vec

我可以在元素0-9(例如,对它们进行排序)上使用线程0,而线程1正在处理元素10-19等吗?

或者我必须使用Vec<Vec<>>吗? (我宁愿避免,因为元素在内存中不再是连续的)

1 个答案:

答案 0 :(得分:10)

是的,你可以。您询问了可变的情况,但我将在前言中说如果Vec是只读的(例如,为了减少),您可以安全地向每个线程中所需的特定切片发送不可变引用。您只需在循环中使用&my_vec[idx1..idx2]之类的内容即可完成此操作。

对于可变的情况,它有点棘手,因为借用跟踪器不够复杂,不允许Vec的非重叠借用。但是,有许多方法,特别是split_at_mut,您可以调用这些方法来获取这些子句。到目前为止,最简单的是chunks_mut迭代器记录here。 (注意,对于不可变的情况,存在匹配的chunks迭代器,因此在编写任何一种情况时只需要进行微小的更改。)

请注意,chunkschunks_mut函数采用每个块的大小,而不是块的数量。但是,从另一个中推导出一个是相当简单的。

但是,我想对可变的案例说几句话。如果均匀分割数据,可能会产生糟糕的性能。原因是CPU不能在单个地址上工作,而是在称为高速缓存行(64字节长)的内存块上工作。如果多个线程在单个缓存行上工作,则必须编写和读取较慢的内存,以确保线程之间的一致性。

不幸的是,在安全的Rust中,没有简单的方法来确定缓存行上Vec的缓冲区的起始位置(因为缓冲区的启动可能已经分配在CPU缓存行的中间),大部分是我所知道的检测方法涉及到实际指针地址的低字节。处理此问题的最简单方法是在要使用的每个块之间添加一个64字节的无意义数据。因此,例如,如果你有一个包含1000个32位浮点数和10个线程的Vec,你只需添加16个具有虚拟值的浮点数(因为32位= 4字节,16 * 4 = 64 = 1高速缓存行)每100个“真实”浮点数之间,并在计算过程中忽略虚拟对象。

这称为虚假共享,我建议您查阅其他参考资料,以了解处理此问题的其他方法。

请注意,x86体系结构保证了64字节的行大小。如果您正在编译ARM,PowerPC,MIPS或其他内容,则此值可能会有所不同。