在julia中读取和写入Float64矩阵的最快方法是什么?

时间:2017-11-17 05:29:35

标签: julia

x = randn(100, 2)。我想将x写入自己的文件。此文件将包含x,只有xx只能是Matrix{Float64}类型。在过去,我总是使用HDF5来解决这个问题,但是我发现这是过度杀戮,因为在这个设置中我每个文件只有一个数组。请注意,JLD使用HDF5,因此也会过度杀死。

1)假设我只想阅读整个矩阵,最快的读写方法是什么x

2)假设我可能想要读取矩阵的一部分,读取和写入x的最快方法是什么?

3)读取和写入x的最快方法是什么,假设我可能想要读取矩阵的切片,或者覆盖矩阵的切片(但< em>不改变矩阵大小)?

3 个答案:

答案 0 :(得分:3)

您可以使用serialize功能,只要您注意文档中有关版本之间的非保证等的警告。

  

serialize(stream :: IO,value)

     

以不透明的格式将任意值写入流,以便可以通过反序列化来回读它。回读值与原始值尽可能相同。一般来说,如果阅读和写作是由不同的完成,这个过程将不起作用     Julia的版本,或具有不同系统映像的Julia的实例。 Ptr值被序列化为全零位模式(NULL)。

     

首先将8字节标识头写入流。要避免编写标头,请构造一个SerializationState并将其用作序列化的第一个参数。另请参见Serializer.writeheader。

实际上,JLD(或者事实上,它的继任者JLD2)通常是推荐的方式*。

*您特别感兴趣的是:“JLD2以包含HDF5子集的格式保存和加载Julia数据结构,而不依赖于HDF5 C库”并且“它通常优于以前的JLD包(有时通过多个数量级),并且通常优于Julia的内置序列化器”

答案 1 :(得分:1)

Julia有两个内置函数readdlm&amp; writedlm执行此操作:

julia> x = randn(5, 5)
5×5 Array{Float64,2}:
 -1.2837    -0.641382  0.611415   0.965762   -0.962764 
  0.106015  -0.344429  1.40278    0.862094    0.324521 
 -0.603751   0.515505  0.381738  -0.167933   -0.171438 
 -1.79919   -0.224585  1.05507   -0.753046    0.0545622
 -0.110378  -1.16155   0.774612  -0.0796534  -0.503871 

julia> writedlm("txtmat.txt", x, use_mmap=true)

julia> readdlm("txtmat.txt", use_mmap=true)
5×5 Array{Float64,2}:
 -1.2837    -0.641382  0.611415   0.965762   -0.962764 
  0.106015  -0.344429  1.40278    0.862094    0.324521 
 -0.603751   0.515505  0.381738  -0.167933   -0.171438 
 -1.79919   -0.224585  1.05507   -0.753046    0.0545622
 -0.110378  -1.16155   0.774612  -0.0796534  -0.503871 

绝对不是最快的方式(如果性能是一个大问题,DanGetz在评论中建议直接使用Mmap.mmap,但似乎这是最简单的方法,输出文件是人类可读的。

答案 2 :(得分:0)

根据上面的Tasos提出的建议,我使用4种不同的方法对写入和读取进行了基本的速度测试:

  1. h5(使用HDF5包)
  2. jld(使用JLD2包)
  3. slz(使用serializedeserialize
  4. dat(写入二进制文件,使用前128位来存储矩阵的维度)
  5. 我已将测试代码粘贴在此答案的底部。结果是:

    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具有最佳性能,而HDF5JLD2和二进制读取的性能相当接近,HDF5略微领先。< / p>

    我还没有考虑过写切片的测试,但将来可能会回到这里。显然,使用serialize无法写入切片(更不用说serialize也面临的版本控制/系统图像问题),而且我不确定如何使用{{1} }。我的直觉是,如果切片在磁盘上是连续的,则将切片写入二进制文件将轻松击败JLD2,但如果它是非连续的,则可能明显慢于HDF5如果HDF5方法最佳地利用分块。如果HDF5没有利用分块(这意味着在写入时知道你想要什么样的切片),那么我怀疑二进制方法将会提前出现。

    总之,我会采用二元方法,因为我认为在这个阶段它显然是整体胜利者。

    我怀疑最终,HDF5可能是选择的方法,但是有一个公平的方法可以去(这里的包本身很新,因此社区没有多少时间进行优化等)

    测试代码如下:

    JLD2