根据上面 Tasos 提出的建议,我使用 4 种不同的方法对写入和读取进行了初步的速度测试:
- h5(使用 HDF5 包)
- jld(使用 JLD2 包)
- slz(使用
serialize和deserialize)
- dat(写入二进制文件,使用前128位存储矩阵的维度)
我已将测试代码粘贴在此答案的底部。结果是:
julia> @time f_write_test(N, "h5")
0.191555 seconds (2.11 k allocations: 76.380 MiB, 26.39% gc time)
julia> @time f_write_test(N, "jld")
0.774857 seconds (8.33 k allocations: 77.058 MiB, 0.32% gc time)
julia> @time f_write_test(N, "slz")
0.108687 seconds (2.61 k allocations: 76.495 MiB, 1.91% gc time)
julia> @time f_write_test(N, "dat")
0.087488 seconds (1.61 k allocations: 76.379 MiB, 1.08% gc time)
julia> @time f_read_test(N, "h5")
0.051646 seconds (5.81 k allocations: 76.515 MiB, 14.80% gc time)
julia> @time f_read_test(N, "jld")
0.071249 seconds (10.04 k allocations: 77.136 MiB, 57.60% gc time)
julia> @time f_read_test(N, "slz")
0.038967 seconds (3.11 k allocations: 76.527 MiB, 22.17% gc time)
julia> @time f_read_test(N, "dat")
0.068544 seconds (1.81 k allocations: 76.405 MiB, 59.21% gc time)
因此,对于写入,写入二进制选项的性能甚至优于 serialize,速度是 HDF5 的两倍,几乎比 JLD2 快一个数量级。
对于读取,deserialize 的性能最好,而HDF5、JLD2 和从二进制读取的性能都相当接近,HDF5 略领先。
我没有包含写入切片的测试,但将来可能会回到这个。显然,使用serialize 写入切片是不可能的(更不用说serialize 也面临的版本控制/系统映像问题),而且我不确定如何使用JLD2 来做到这一点。如果切片在磁盘上是连续的,我的直觉将切片写入二进制很容易击败HDF5,但如果它是非连续的,则可能会比HDF5慢得多如果@987654336 @ 方法最佳地利用了分块。如果HDF5 没有利用分块(这意味着在写入时知道你需要什么切片),那么我怀疑二进制方法会出现。
总而言之,我将采用二元法,因为我认为现阶段它显然是总体赢家。
我怀疑最终,JLD2 可能会成为首选方法,但这里有一个公平的方法(包本身非常新,因此社区没有太多时间进行优化等工作)。
测试代码如下:
using JLD2, HDF5
f_write_h5(fp::String, x::Matrix{Float64}) = h5write(fp, "G/D", x)
f_write_jld(fp::String, x::Matrix{Float64}) = @save fp x
f_write_slz(fp::String, x::Matrix{Float64}) = open(fid->serialize(fid, x), fp, "w")
f_write_dat_inner(fid1::IOStream, x::Matrix{Float64}) = begin ; write(fid1, size(x,1)) ; write(fid1, size(x,2)) ; write(fid1, x) ; end
f_write_dat(fp::String, x::Matrix{Float64}) = open(fid1->f_write_dat_inner(fid1, x), fp, "w")
f_read_h5(fp::String) = h5read(fp, "G/D")
f_read_jld(fp::String) = @load fp x
f_read_slz(fp::String) = open(deserialize, fp, "r")
f_read_dat_inner(fid1::IOStream) = begin ; d1 = read(fid1, Int) ; d2 = read(fid1, Int) ; read(fid1, Float64, (d1, d2)) ; end
f_read_dat(fp::String) = open(f_read_dat_inner, fp, "r")
function f_write_test(N::Int, filetype::String)
dp = "/home/colin/Temp/"
filetype == "h5" && [ f_write_h5("$(dp)$(n).$(filetype)", randn(1000, 100)) for n = 1:N ]
filetype == "jld" && [ f_write_jld("$(dp)$(n).$(filetype)", randn(1000, 100)) for n = 1:N ]
filetype == "slz" && [ f_write_slz("$(dp)$(n).$(filetype)", randn(1000, 100)) for n = 1:N ]
filetype == "dat" && [ f_write_dat("$(dp)$(n).$(filetype)", randn(1000, 100)) for n = 1:N ]
#[ rm("$(dp)$(n).$(filetype)") for n = 1:N ]
nothing
end
function f_read_test(N::Int, filetype::String)
dp = "/home/colin/Temp/"
filetype == "h5" && [ f_read_h5("$(dp)$(n).$(filetype)") for n = 1:N ]
filetype == "jld" && [ f_read_jld("$(dp)$(n).$(filetype)") for n = 1:N ]
filetype == "slz" && [ f_read_slz("$(dp)$(n).$(filetype)") for n = 1:N ]
filetype == "dat" && [ f_read_dat("$(dp)$(n).$(filetype)") for n = 1:N ]
[ rm("$(dp)$(n).$(filetype)") for n = 1:N ]
nothing
end
f_write_test(1, "h5")
f_write_test(1, "jld")
f_write_test(1, "slz")
f_write_test(1, "dat")
f_read_test(1, "h5")
f_read_test(1, "jld")
f_read_test(1, "slz")
f_read_test(1, "dat")
N = 100
@time f_write_test(N, "h5")
@time f_write_test(N, "jld")
@time f_write_test(N, "slz")
@time f_write_test(N, "dat")
@time f_read_test(N, "h5")
@time f_read_test(N, "jld")
@time f_read_test(N, "slz")
@time f_read_test(N, "dat")