我有10个主题,长度为100的Vec
。
我可以在元素0-9(例如,对它们进行排序)上使用线程0,而线程1正在处理元素10-19等吗?
或者我必须使用Vec<Vec<>>
吗? (我宁愿避免,因为元素在内存中不再是连续的)
答案 0 :(得分:10)
是的,你可以。您询问了可变的情况,但我将在前言中说如果Vec
是只读的(例如,为了减少),您可以安全地向每个线程中所需的特定切片发送不可变引用。您只需在循环中使用&my_vec[idx1..idx2]
之类的内容即可完成此操作。
对于可变的情况,它有点棘手,因为借用跟踪器不够复杂,不允许Vec
的非重叠借用。但是,有许多方法,特别是split_at_mut
,您可以调用这些方法来获取这些子句。到目前为止,最简单的是chunks_mut
迭代器记录here。 (注意,对于不可变的情况,存在匹配的chunks
迭代器,因此在编写任何一种情况时只需要进行微小的更改。)
请注意,chunks
和chunks_mut
函数采用每个块的大小,而不是块的数量。但是,从另一个中推导出一个是相当简单的。
不幸的是,在安全的Rust中,没有简单的方法来确定缓存行上Vec
的缓冲区的起始位置(因为缓冲区的启动可能已经分配在CPU缓存行的中间),大部分是我所知道的检测方法涉及到实际指针地址的低字节。处理此问题的最简单方法是在要使用的每个块之间添加一个64字节的无意义数据。因此,例如,如果你有一个包含1000个32位浮点数和10个线程的Vec
,你只需添加16个具有虚拟值的浮点数(因为32位= 4字节,16 * 4 = 64 = 1高速缓存行)每100个“真实”浮点数之间,并在计算过程中忽略虚拟对象。
这称为虚假共享,我建议您查阅其他参考资料,以了解处理此问题的其他方法。
请注意,x86体系结构保证了64字节的行大小。如果您正在编译ARM,PowerPC,MIPS或其他内容,则此值可能会有所不同。