用Julia Mmap复制一个大文件
我有一个大文件(75GB)内存映射到一个数组用Julia Mmap复制一个大文件,julia,memory-mapped-files,Julia,Memory Mapped Files,我有一个大文件(75GB)内存映射到一个数组d,我想复制到另一个m中。因为我没有可用的75GB RAM,所以我做到了: for (i,v) in enumerate(d) m[i] = v end 以便在值之后复制文件值。但我在SSD上获得了约2MB/s的拷贝速率,我希望读写速度至少为50MB/s 如何优化此复制速率 ==[编辑]=== 根据评论,我将代码更改为以下代码,从而将写入速率提高到15MB/s function copydcimg(m::Array{UInt16,4}, d:
d
,我想复制到另一个m
中。因为我没有可用的75GB RAM,所以我做到了:
for (i,v) in enumerate(d)
m[i] = v
end
以便在值之后复制文件值。但我在SSD上获得了约2MB/s的拷贝速率,我希望读写速度至少为50MB/s
如何优化此复制速率
==[编辑]===
根据评论,我将代码更改为以下代码,从而将写入速率提高到15MB/s
function copydcimg(m::Array{UInt16,4}, d::Dcimg)
m .= d
Mmap.sync!(m)
end
copydcimg(m,d)
此时,我认为应该优化Dcimg代码。这个二进制文件由帧组成,帧之间用时间戳隔开。下面是我用来访问帧的代码:
module dcimg
using Mmap
using TOML
struct Dcimg <: AbstractArray{UInt16,4} # struct allowing to access dcimg file
filename::String # filename of the dcimg
header::Int # header size in bytes
clock::Int # clock size in bytes
x::Int
y::Int
z::Int
t::Int
m # linear memory map
Dcimg(filename, header, clock, x, y, z, t) =
new(filename, header, clock, x, y, z, t,
Mmap.mmap(open(filename), Array{UInt16, 3},
(x*y+clock÷sizeof(UInt16), z, t), header)
)
end
# following functions allows to access DCIMG like an Array
Base.size(D::Dcimg) = (D.x, D.y, D.z, D.t)
# skip clock
Base.getindex(D::Dcimg, i::Int) =
D.m[i + (i ÷ (D.x*D.y))*D.clock÷sizeof(UInt16)]
Base.getindex(D::Dcimg, x::Int, y::Int, z::Int, t::Int) =
D[x + D.x*((y-1) + D.y*((z-1) + D.z*(t-1)))]
# allowing to automatically parse size
function Dcimg(pathtag)
p = TOML.parsefile(pathtag * ".toml")
return Dcimg(pathtag * ".dcimg",
# ...
)
end
export Dcimg, getframe
end
模块dcimg
使用Mmap
使用TOML
struct Dcimg我明白了!解决方案是逐块复制文件,比如说逐帧复制(大约1024×720 UInt16)。这样我达到了300MB/s,我甚至不知道在单线程中是可能的。这是代码
在模块dcimg中,我添加了逐帧访问文件的方法
# get frame number n (starting form 1)
getframe(D::Dcimg,n::Int) =
reshape(D.m[
D.x*D.y*(n-1)+1 + (n-1)*D.clock÷sizeof(UInt16) : # cosmetic line break
D.x*D.y*n + (n-1)*D.clock÷sizeof(UInt16)
], D.x, D.y)
# get frame for layer z, time t (starting from 1)
getframe(D::Dcimg,z::Int,t::Int) =
getframe(D::Dcimg,(z-1)+D.z*(t-1))
在循环中的帧上迭代
function copyframes(m::Array{UInt16,4}, d::Dcimg)
N = d.z*d.t
F = d.x*d.y
for i in 1:N
m[(i-1)*F+1:i*F] = getframe(d, i)
end
end
copyframes(m,d)
感谢所有的评论引导我这么做
======编辑=====
要进一步阅读,您可以查看:
它给出了一次要复制的最佳块大小的提示。您是在全局范围内还是在函数内执行此代码段?将其包装在函数中,并将d
和m
作为参数传递,因为参数可能会有所帮助。如果它只是复制,中间没有其他代码:是否比较了copy代码>@张实唯 我目前正在运行一个脚本。为什么你认为包装会改变一些事情?@Hugortentesaux,copy
从一个Mmap数组读取值并写入另一个,前提是您的Mmap数组持有bits类型,这是必须的。如果运行copy,则应更改m
的文件内容!(m,d);Mmap.sync!(m)
,或m.=d;Mmap.sync!(m)
,应更新m
的磁盘内容。如果将代码段放入函数中,它将被编译并运行得更快。您的代码片段没有包装到函数中,可能会造成瓶颈,尽管我不认为瓶颈会像2MB/s那么严重。@Hugortentesaux,因为这是本文的第一个技巧,如果您使用线性方案访问mmap阵列,我认为这些修改不是真的必要。我认为真正的问题是你没有给Dcimg.m
一个类型,这使得你的代码类型不稳定,每次都是指m
。在您的struct Dcimg
中将m
定义为m::Array{UInt16,3}
之后,您能否在一个较小的文件上测试速度(我不希望您佩戴SSD)?我也不能理解你的getindex
方案,特别是Base.getindex(D::Dcimg,I::Int)
。虽然在复制操作期间不使用此函数,但是AFAIK.您是对的,添加::数组{UInt16,3}可以使我达到150MB/s,这很好。我认为速度的进一步提高是由于逐块读取而不是在读和写之间快速切换,但我不能确定。我认为你也是对的!我没有考虑这个费用。但是对于类型稳定性,请记住为struct
字段指定一个类型。否则,您的函数将输入不稳定并最终变慢。谢谢您的建议。我认为类型可以从构造函数中推断出来,因为这是在这个例子中设置字段的唯一方法,但我现在理解了我的错误。