通常,基准测试用于比较语言。这些基准引发长时间的讨论,首先是关于什么是基准测试,其次是解释差异的原因。这些简单的问题有时会比你最初想象的要复杂得多。
概要
定义和函数
总结的实施和基准测试...
C(hand-written)
C(with -ffast-math)
Python(built-in)
Python(numpy)
Python(hand-written)
Julia(built-in)
Julia(hand-written)
Julia(hand-written w.simd)
基准总结
:一个容易理解的功能
考虑计算和的sum函数sum(a)
n
sum()=,
=1
代指的长度
a=rand(10^7)# 产生随机向量
sun(a)
预期结果是0.5 * 10 ^ 7,因为每个条目的平均值是0.5
用几种语言,几种方法进行基准测试
@timesum(a)
宏可以产生嘈杂的结果,因此它不是我们进行基准测试的最佳选择!幸运的是,Julia有一个人BenchmarkTools.jl包,可以轻松准确地进行基准测试:
#using Pkg
#Pkg.add("BenchmarkTools")
usingBenchmarkTools
1.C语言
C通常被认为是黄金标准:对人类很不友好,但对机器而言很友好。 达到C的2倍通常是令人满意的。 尽管如此,即使在C语言中,也有很多种可能的优化,一个C作者可能会或又可能不会去优化。
很高兴地告诉你可以将C代码放入Julia会话,编译并运行它。 请注意,”“”多行字符串。
usingLibdl
C_code="""
#include
double c_sum(size_t n, double *X) {
double s = 0.0;
for (size_t i = 0; i
s += X[i];
}
return s;
}
"""
constClib=tempname()# make a temporary file
# compile to a shared library by piping C_code to gcc
# (works only if you have gcc installed):
open(`gcc -fPIC -O3 -msse3 -xc -shared -o $(Clib * "." * Libdl.dlext) -`,"w")dof
print(f,C_code)
end
# define a Julia function that calls the C function:
c_sum(X::Array)=ccall(("c_sum",Clib),Float64, (Csize_t,Ptr{Float64}),length(X),X)
isapprox
我们现在可以直接从Julia对C代码进行基准测试:
d=Dict()#a"dictionary",i.e.anassociativearray
d["C"]=minimum(c_bench.times)/1e6#inmilliseconds
d
using Plots
gr()
using Statistics # bring in statistical support for standard deviations
t = c_bench.times / 1e6 # times in milliseconds
m, σ = minimum(t), std(t)
histogram(t, bins=500,
xlim=(m - 0.01, m + σ),
xlabel="milliseconds", ylabel="count", label="")
2.C with -ffast-math
如果我们允许C重 新安排浮点运算,那么他将使用SIMD(单指令,多数据)指令进行向量化
const Clib_fastmath = tempname() # make a temporary file
# The same as above but with a -ffast-math flag added
open(`gcc -fPIC -O3 -msse3 -xc -shared -ffast-math -o $(Clib_fastmath * "." * Libdl.dlext) -`, "w") do f
print(f, C_code)
end
# define a Julia function that calls the C function:
c_sum_fastmath(X::Array) = ccall(("c_sum", Clib_fastmath), Float64, (Csize_t, Ptr), length(X), X)
3.Python's built in sum
PyCall包为Python提供了Julia接口:
# using Pkg;Pkg.add("PyCall")
using PyCall
# get the Python built-in "sum" function
pysum=pybuiltin("sum")
pysum(a)
pysum(a)≈sum(a)
py_list_bench=@benchmark$pysum($a)
d["Python built-in"]=minimum(py_list_bnech.times)/1e6
print(d)
4.Python:numpy
利用硬件“SIMD”,但只在它工作是才有效。numpy是一个优秀的C库,可以从Python调用。它可以安装在 Julia中,如下所示
# using Pkg;Pkg.add("Conda")
usingConda
# Conda.add("numpy")
numpy_sum=pyimport("numpy")["sum"]
py_numpy_bench=@benchmark$numpy_sum($a)
numpy_sum(a)
numpy_sum(a)≈sum(a)
d["Python numpy"]=minimum(py_numpy_bench.times)/1e6
print(d)
5.Python,hand-written
py"""
def py_sum(A):
s=0.0
for a in A:
s += a
return s
"""
sum_py=py"py_sum"
py_hand=@benchmark$sum_py($a)
sum_py(a)
sum_py(a)≈sum(a)
d["Python hand-written"] =minimum(py_hand.times)/1e6
print(d)
6.Julia (built-in)
在Julia中书写 ,不是在C中
@whichsum(a)
j_bench=@benchmarksum($a)
d["Julia built-in"]=minimum(j_bench.times)/1e6
print(d)
7.Julia (hand-written)
functionmysum(A)
s=0.0#s = zero(eltype(a))
forainA
s+=a
end
s
end
j_bench_hand=@benchmarkmysum($a)
d["Julia hand-written"]=minimum(j_bench_hand.times)/1e6
print(d)
8.Julia(hand-written w.simd)
functionmysum_simd(A)
s=0.0#s = zero(elype(A))
@simdforainA
s+=a
end
s
end
j_bench_hand_simd=@benchmarkmysum_simd($a)
mysum_simd(a)
d["Julia hand-written simd"]=minimum(j_bench_hand_simd.times)/1e6
print(d)
9. Summary
for(key,value)in sort(collect(d),by=last)
println(rpad(key,25,"."),lpad(round(value;digits=1),6,"."))
end
领取专属 10元无门槛券
私享最新 技术干货