用Julia Mmap复制一个大文件

用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:

我有一个大文件(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::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
字段指定一个类型。否则,您的函数将输入不稳定并最终变慢。谢谢您的建议。我认为类型可以从构造函数中推断出来,因为这是在这个例子中设置字段的唯一方法,但我现在理解了我的错误。