我有一个相当大的矩形(>1G行,1K列)Fortran风格的NumPy矩阵,我想将其转置为C风格。
到目前为止,我的方法相对简单,使用以下Rust代码片段,使用源矩阵和目标矩阵的MMAPed切片,其中original_matrix
和target_matrix
都是MMAPPed PyArray2
,并且使用Rayon处理并行化。
由于target_matrix
必须由多个线程修改,因此我将其包装在一个UnsafeCell
中。
let shared_target_matrix = std::cell::UnsafeCell::new(target_matrix);
original_matrix.as_ref().par_chunks(number_of_nodes).enumerate().for_each(|(j, feature)|{
feature.iter().copied().enumerate().for_each(|(i, feature_value)| unsafe {
*(shared_target_matrix.uget_mut([i, j])) = feature_value;
});
});
这种方法可以对形状为(~1G,100)的矩阵进行转置,在HDD磁盘上需要大约120GB且需要3小时。然而,对于形状为(~1G,1000), ~1200GB的矩阵来说,它并不像天真地预期的那样线性扩展到30个小时,而是会爆炸式增长到数周的时间。目前为止,我已经在2天内成功地转置了大约100个特征,并且速度仍在变慢。
有一些方面,例如所使用的文件系统、HDD碎片整理以及MMAPed处理页面加载的方式,我的解决方案目前正在忽略这些问题。
是否已知有更全面的解决方案考虑了这些问题?
关于顺序和并行方法的说明
尽管直觉上,这种操作可能仅受IO限制,因此不受任何并行化的好处,但我们实验上观察到,并行方法比顺序方法快约三倍(在具有12个核心和24个线程的机器上),当转置一个形状为(1G,100)的矩阵时。我们不确定为什么会出现这种情况。
使用两个HDD的说明
我们还尝试使用两个设备,一个提供Fortran风格的矩阵,另一个用于写入目标矩阵。两个HDD通过SATA电缆直接连接到计算机主板。我们期望至少可以将性能提高一倍,但实际表现并没有改变。
rayon
在这里并没有帮助。事实上,它甚至可能通过强制更复杂的HDD访问模式来减慢速度,而单线程程序则可以拥有更规律(因此更快)的访问。 - Jmb