Arrays julia:实现VCN阵列的有效方法
我有一个从json加载的数据结构,如下所示Arrays julia:实现VCN阵列的有效方法,arrays,julia,Arrays,Julia,我有一个从json加载的数据结构,如下所示 json_in = [ Dict("customer" => "cust1", "transactions" => 1:10^6) , Dict("customer" => "cust2", "transactions" => 1:10^6) , Dict("customer" => "cust3", "transactions" => 1:10^6)] 我知道有两种方法可以将事务折叠到一个数组中 @t
json_in =
[ Dict("customer" => "cust1", "transactions" => 1:10^6)
, Dict("customer" => "cust2", "transactions" => 1:10^6)
, Dict("customer" => "cust3", "transactions" => 1:10^6)]
我知道有两种方法可以将事务折叠到一个数组中
@time methodA = reduce(vcat,[cust["transactions"] for cust in json_in])
@time methodB = vcat(json_in[1]["transactions"],json_in[2]["transactions"],json_in[3]["transactions"])
但是,在我的计算机上,methodA的计时为~0.22秒,methodB的计时为~0.02秒。我打算执行这数千次,因此10倍更快的性能是一件大事
我看到methodB不是很健壮,因为它只能处理3个Dicts客户,所以即使它的性能很好,也不能推广
高效连接Dict数组中元素的数组的最有效方法是什么?正如@Gnimuc在其评论中所述,您不应该在全局范围内进行基准测试,最好使用BenchmarkTools.jl进行基准测试-以下是正确完成的时间安排:
julia> methodA(json_in) = reduce(vcat,[cust["transactions"] for cust in json_in])
method1 (generic function with 1 method)
julia> methodB(json_in) = vcat(json_in[1]["transactions"],json_in[2]["transactions"],json_in[3]["transactions"])
method2 (generic function with 1 method)
#Gnimuc's syntax from his comment
julia> methodC(json_in) = mapreduce(x->x["transactions"], vcat, json_in)
method3 (generic function with 1 method)
julia> using BenchmarkTools
julia> @benchmark methodA(json_in)
BenchmarkTools.Trial:
memory estimate: 38.15 MiB
allocs estimate: 15
--------------
minimum time: 10.584 ms (3.10% GC)
median time: 14.781 ms (32.02% GC)
mean time: 15.112 ms (32.19% GC)
maximum time: 69.341 ms (85.28% GC)
--------------
samples: 331
evals/sample: 1
julia> @benchmark methodB(json_in)
BenchmarkTools.Trial:
memory estimate: 22.89 MiB
allocs estimate: 2
--------------
minimum time: 5.921 ms (5.92% GC)
median time: 8.402 ms (32.48% GC)
mean time: 8.701 ms (33.46% GC)
maximum time: 69.268 ms (91.09% GC)
--------------
samples: 574
evals/sample: 1
julia> @benchmark methodC(json_in)
BenchmarkTools.Trial:
memory estimate: 38.15 MiB
allocs estimate: 12
--------------
minimum time: 10.599 ms (3.37% GC)
median time: 14.843 ms (32.12% GC)
mean time: 15.228 ms (32.24% GC)
maximum time: 71.954 ms (85.95% GC)
--------------
samples: 328
evals/sample: 1
方法B的速度仍然是原来的两倍。这正是因为它更专业化,在一个只有三个元素的数组上
另一种可能在这里工作得很好的解决方案是使用Mappedaray,它在原始数组中创建一个惰性视图:
using MappedArrays
method4(json_in) = mappedarray(x->x["transactions"], json_in)
当然,这不会连接阵列,但可以使用CatView包连接视图:
using CatViews
julia> method5(json_in) = reduce(CatView, mappedarray(x->x["transactions"], json_in))
method5 (generic function with 1 method)
julia> @benchmark method5(json_in)
BenchmarkTools.Trial:
memory estimate: 1.73 KiB
allocs estimate: 46
--------------
minimum time: 23.320 μs (0.00% GC)
median time: 23.916 μs (0.00% GC)
mean time: 25.466 μs (0.00% GC)
maximum time: 179.092 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
因为它不分配,所以它比方法B快300倍,但使用结果可能较慢,因为非局部性-值得进行基准测试。正如@Gnimuc在其评论中所述,您不应该在全局范围内进行基准测试,最好使用BenchmarkTools.jl进行基准测试-以下是正确完成的时间安排:
julia> methodA(json_in) = reduce(vcat,[cust["transactions"] for cust in json_in])
method1 (generic function with 1 method)
julia> methodB(json_in) = vcat(json_in[1]["transactions"],json_in[2]["transactions"],json_in[3]["transactions"])
method2 (generic function with 1 method)
#Gnimuc's syntax from his comment
julia> methodC(json_in) = mapreduce(x->x["transactions"], vcat, json_in)
method3 (generic function with 1 method)
julia> using BenchmarkTools
julia> @benchmark methodA(json_in)
BenchmarkTools.Trial:
memory estimate: 38.15 MiB
allocs estimate: 15
--------------
minimum time: 10.584 ms (3.10% GC)
median time: 14.781 ms (32.02% GC)
mean time: 15.112 ms (32.19% GC)
maximum time: 69.341 ms (85.28% GC)
--------------
samples: 331
evals/sample: 1
julia> @benchmark methodB(json_in)
BenchmarkTools.Trial:
memory estimate: 22.89 MiB
allocs estimate: 2
--------------
minimum time: 5.921 ms (5.92% GC)
median time: 8.402 ms (32.48% GC)
mean time: 8.701 ms (33.46% GC)
maximum time: 69.268 ms (91.09% GC)
--------------
samples: 574
evals/sample: 1
julia> @benchmark methodC(json_in)
BenchmarkTools.Trial:
memory estimate: 38.15 MiB
allocs estimate: 12
--------------
minimum time: 10.599 ms (3.37% GC)
median time: 14.843 ms (32.12% GC)
mean time: 15.228 ms (32.24% GC)
maximum time: 71.954 ms (85.95% GC)
--------------
samples: 328
evals/sample: 1
方法B的速度仍然是原来的两倍。这正是因为它更专业化,在一个只有三个元素的数组上
另一种可能在这里工作得很好的解决方案是使用Mappedaray,它在原始数组中创建一个惰性视图:
using MappedArrays
method4(json_in) = mappedarray(x->x["transactions"], json_in)
当然,这不会连接阵列,但可以使用CatView包连接视图:
using CatViews
julia> method5(json_in) = reduce(CatView, mappedarray(x->x["transactions"], json_in))
method5 (generic function with 1 method)
julia> @benchmark method5(json_in)
BenchmarkTools.Trial:
memory estimate: 1.73 KiB
allocs estimate: 46
--------------
minimum time: 23.320 μs (0.00% GC)
median time: 23.916 μs (0.00% GC)
mean time: 25.466 μs (0.00% GC)
maximum time: 179.092 μs (0.00% GC)
--------------
samples: 10000
evals/sample: 1
因为它不分配,所以比方法B快300倍,但使用结果可能会慢一些,因为非局部性-值得进行基准测试。感谢您的帮助,经过一些研究后,我想到了使用宏内联扩展代码的想法,请参阅下面的代码,它在Juliabox.com 2017年9月21日的基准测试中表现良好
macro inline_vcat(a)
quote
astr = $(string(a))
s = reduce(string, string(astr,"[",aa,"][\"transactions\"],") for aa in 1:length($a))
string("vcat(", s[1:(end-1)],")")
end
end
methodE(json_in) = (@inline_vcat json_in) |> parse |> eval
using BenchmarkTools
@benchmark methodE(json_in)
这种方法的一个缺点是,如果JSON中有大量~100万客户,那么生成的代码将很长,我认为解析它需要很长时间。因此,对于大型数据集来说,这可能不是一个好主意。感谢您的帮助,经过一些研究,我提出了使用宏内联扩展代码的想法,请参见下面的代码,它在Juliabox.com 2017年9月21日的基准测试中表现得非常好
macro inline_vcat(a)
quote
astr = $(string(a))
s = reduce(string, string(astr,"[",aa,"][\"transactions\"],") for aa in 1:length($a))
string("vcat(", s[1:(end-1)],")")
end
end
methodE(json_in) = (@inline_vcat json_in) |> parse |> eval
using BenchmarkTools
@benchmark methodE(json_in)
这种方法的一个缺点是,如果JSON中有大量~100万客户,那么生成的代码将很长,我认为解析它需要很长时间。因此,对于大型数据集来说,这可能不是一个好主意。提示:不要在全局范围内进行基准测试。您也可以在中使用mapreducex->x[transactions],vcat,json_,而不是reduce+comprehension。此外,我自己未回答的问题可能会重复,您可能会感兴趣。其中包含一些相关代码:@Gnimuc我认为mapreduce不会更快,因为我的reduce for组合就像mapreduce一样?是的,这里没有性能原因。只是因为它的语法比组合的reduce更简洁;提示:不要在全局范围内进行基准测试。您也可以在中使用mapreducex->x[transactions],vcat,json_,而不是reduce+comprehension。此外,我自己未回答的问题可能会重复,您可能会感兴趣。其中包含一些相关代码:@Gnimuc我认为mapreduce不会更快,因为我的reduce for组合就像mapreduce一样?是的,这里没有性能原因。只是因为它的语法比组合的reduce更简洁;