首页 > 解决方案 > 使用 Julia Mmap 复制一个大文件

问题描述

我有一个大文件(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

标签: juliamemory-mapped-files

解决方案


我知道了!解决方案是逐块复制文件,比如说逐帧(大约 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)

感谢所有在评论中引导我这样做的人。

===== 编辑 =====

如需进一步阅读,您可以查看:

它给出了一次复制的最佳块大小的提示。


推荐阅读