为什么Boost';与Julia';什么是快速排序? < >我比较了朱丽亚和C++之间的性能。然后我发现Julia中的快速排序速度要快得多(甚至比C++还要快),特别是当数组的大小非常大时
有人能解释一下原因吗 快速排序.jl为什么Boost';与Julia';什么是快速排序? < >我比较了朱丽亚和C++之间的性能。然后我发现Julia中的快速排序速度要快得多(甚至比C++还要快),特别是当数组的大小非常大时,c++,performance,julia,benchmarking,quicksort,C++,Performance,Julia,Benchmarking,Quicksort,有人能解释一下原因吗 快速排序.jl include("../dimension.jl") function execute() n = getDimension() print(stderr, "Julia,quickSort_optim,$n,"); # use default delimiter arr = zeros(Int32, n) for i = 1:n arr[i] = (777*(i-
include("../dimension.jl")
function execute()
n = getDimension()
print(stderr, "Julia,quickSort_optim,$n,"); # use default delimiter
arr = zeros(Int32, n)
for i = 1:n
arr[i] = (777*(i-1)) % 10000
end
if n > 0
sort!(arr; alg=QuickSort)
end
end
# executing ...
execute()
快速排序\u boost.cpp
#include "dimension.h"
#include <boost/lambda/lambda.hpp>
#include <boost/sort/pdqsort/pdqsort.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
using namespace std;
using namespace boost::sort;
int main()
{
int n = getDimension();
cerr << "C++,quickSort_boost," << n << ",";
vector<int> arr(n);
unsigned long long w;
for(int i = 0; i < n; ++i){ // array for sorting
w = (777*i) % 10000; // Array with values between 0 and 10000
arr[i] = w;
}
if (n > 0){
pdqsort_branchless(arr.begin(), arr.end(), [](const int &a, const int &b){return ( a < b );});
}
return 0;
}
#包括“dimension.h”
#包括
#包括
#包括
#包括
#包括
注意
函数getDimension()用于获取数组大小
执行时间是通过Ubuntu下的shell命令:/usr/bin/time来测量的。编译器:clang版本6.0.0-1ubuntu2。优化级别:-02。CPU:Intel i7-3820QM
我之所以比较整个执行时间而不仅仅是算法本身,是因为我想比较这两种语言之间的性能,这模拟了一个真实的应用程序场景
在Julia的官方文档中,它写道:快速排序:对于大型集合,性能良好。
这是因为Julia在算法中使用了一个特殊的实现
更多样本
我用更多的样本进行测试。似乎数据的分布是个问题。
广泛分布数据的最佳情况:
function execute()#用于指定数据的代码段
对于i=1:n
arr[i]=i
结束
对于(int i=0;i<n;++i){//C++ +增强代码段来指定数据
arr[i]=i+1;
}
数据分布广泛的最坏情况:
function execute()#用于指定数据的代码段
对于i=1:n
arr[i]=n-i+1
结束
对于(int i=0;i<n;++i){//C++ +增强代码段来指定数据
arr[i]=n-i;
}
集中分布数据
function execute()#用于指定数据的代码段
对于i=1:n
arr[i]=i%10
结束
对于(int i=0;i<n;++i){//C++ +增强代码段来指定数据
arr[i]=(i+1)%10;
}
不确定计时是怎么回事–您没有包含足够的代码来测试或复制。快速排序的Julia代码非常简单,您可以在此处查看其源代码:
为了便于阅读,我还将在此处提供代码:
@inline function selectpivot!(v::AbstractVector, lo::Integer, hi::Integer, o::Ordering)
@inbounds begin
mi = midpoint(lo, hi)
# sort v[mi] <= v[lo] <= v[hi] such that the pivot is immediately in place
if lt(o, v[lo], v[mi])
v[mi], v[lo] = v[lo], v[mi]
end
if lt(o, v[hi], v[lo])
if lt(o, v[hi], v[mi])
v[hi], v[lo], v[mi] = v[lo], v[mi], v[hi]
else
v[hi], v[lo] = v[lo], v[hi]
end
end
# return the pivot
return v[lo]
end
end
function partition!(v::AbstractVector, lo::Integer, hi::Integer, o::Ordering)
pivot = selectpivot!(v, lo, hi, o)
# pivot == v[lo], v[hi] > pivot
i, j = lo, hi
@inbounds while true
i += 1; j -= 1
while lt(o, v[i], pivot); i += 1; end;
while lt(o, pivot, v[j]); j -= 1; end;
i >= j && break
v[i], v[j] = v[j], v[i]
end
v[j], v[lo] = pivot, v[j]
# v[j] == pivot
# v[k] >= pivot for k > j
# v[i] <= pivot for i < j
return j
end
function sort!(v::AbstractVector, lo::Integer, hi::Integer, a::QuickSortAlg, o::Ordering)
@inbounds while lo < hi
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
j = partition!(v, lo, hi, o)
if j-lo < hi-j
# recurse on the smaller chunk
# this is necessary to preserve O(log(n))
# stack space in the worst case (rather than O(n))
lo < (j-1) && sort!(v, lo, j-1, a, o)
lo = j+1
else
j+1 < hi && sort!(v, j+1, hi, a, o)
hi = j-1
end
end
return v
end
@内联函数选择Pivot!(v::AbstractVector、lo::Integer、hi::Integer、o::Ordering)
@内边界开始
mi=中点(低、高)
#排序v[mi]=j&&break
v[i],v[j]=v[j],v[i]
结束
v[j],v[lo]=枢轴,v[j]
#v[j]==枢轴
#v[k]>=k>j的枢轴
#五[一]摘要
TL;DRJulia和C++的std::sort
在性能上非常接近。Boost的pdqsort_无分支
更快
外卖钥匙
方法:
只衡量什么是重要的。在代码中,您还可以测量生成向量的设置时间
请注意,测试数据的分布与“生产”数据的分布具有可比性
确保编译时使用-march=native-mtune=native
代码:
- Boost的pdqsort_无分支
更快。STL的std::sort
和Julia的排序在运行时性能上相当接近
qsort
,后者速度较慢。这就是为什么我不再进一步展示它的原因- 我使用脚本进行绘图
- 如果标签太小:
- 蓝色/最快:boost的类型
- 绿色和红色:
和Juliastd::sort
C++,使用库.< /P> 为方便起见,您可以通过以下网址在线访问:。以下是代码:
这允许您指定要度量代码的哪一部分。它还可以正确地进行测量和统计 下面是一个例子:静态无效示例(基准::状态和状态){
std::矢量数据(1024);
std::iota(data.begin(),data.end(),0);
std::mt19937 mersenne_引擎{1234};
用于(自动:状态){
state.pauseting();
std::shuffle(data.begin()、data.end()、mersenne_引擎);
state.ResumeTiming();
std::sort(data.begin(),data.end());
}
}
基准(示例);
Google Benchmark只测量(auto uuz:state){…}块(计时块)的内部的代码。因此,上面的代码避免了测量设置时间的陷阱
在每次运行之前,数据是shuffle
d
朱莉娅
使用BenchmarkTools
库,其中的基准测试如下:
Random.seed!(1234)
function make_vec(n)
return Random.randperm(Int32(n));
end
@benchmark sort!(arr; alg=QuickSort) setup=(arr=make_vec(1024));
数据生成
我们需要澄清您生成数据的方式
正如您所发现的,算法在已经排序的数据上运行得最快,而在反向排序的数据上运行得更差
最后,需要知道基准算法运行的领域知识。数据分布的形状是什么
随机数据
首先,让我们使用[01000]
中均匀分布的数据。比在已经排序的数据上测试要好得多
我使用的是一个固定的种子,所以每次的数据都是相同的(对于给定的N)。如果使用rnd_device()
实例化mersenne_引擎
,每次都会得到不同的种子,从而得到不同的数据。就个人而言,我喜欢使用随机但一致的数据,以减少结果的变化。请记住这一点,以便以后进行分析
请注意,生成0到10k之间的数据将导致输入数量级大于10k的大量重复
洗牌数据
如果不希望有重复项,则生成包含元素[0,1,2,…,N]
的向量,然后对数据进行无序排列
我是这样做的:
//创建填充了0..n的向量
std::向量arr(n);
s
function execute() # julia code segment for specifying data
for i = 1:n
arr[i] = i % 10
end
for(int i = 0; i < n; ++i){ // c++ boost code segment for specifying data
arr[i] = (i + 1) % 10;
}
@inline function selectpivot!(v::AbstractVector, lo::Integer, hi::Integer, o::Ordering)
@inbounds begin
mi = midpoint(lo, hi)
# sort v[mi] <= v[lo] <= v[hi] such that the pivot is immediately in place
if lt(o, v[lo], v[mi])
v[mi], v[lo] = v[lo], v[mi]
end
if lt(o, v[hi], v[lo])
if lt(o, v[hi], v[mi])
v[hi], v[lo], v[mi] = v[lo], v[mi], v[hi]
else
v[hi], v[lo] = v[lo], v[hi]
end
end
# return the pivot
return v[lo]
end
end
function partition!(v::AbstractVector, lo::Integer, hi::Integer, o::Ordering)
pivot = selectpivot!(v, lo, hi, o)
# pivot == v[lo], v[hi] > pivot
i, j = lo, hi
@inbounds while true
i += 1; j -= 1
while lt(o, v[i], pivot); i += 1; end;
while lt(o, pivot, v[j]); j -= 1; end;
i >= j && break
v[i], v[j] = v[j], v[i]
end
v[j], v[lo] = pivot, v[j]
# v[j] == pivot
# v[k] >= pivot for k > j
# v[i] <= pivot for i < j
return j
end
function sort!(v::AbstractVector, lo::Integer, hi::Integer, a::QuickSortAlg, o::Ordering)
@inbounds while lo < hi
hi-lo <= SMALL_THRESHOLD && return sort!(v, lo, hi, SMALL_ALGORITHM, o)
j = partition!(v, lo, hi, o)
if j-lo < hi-j
# recurse on the smaller chunk
# this is necessary to preserve O(log(n))
# stack space in the worst case (rather than O(n))
lo < (j-1) && sort!(v, lo, j-1, a, o)
lo = j+1
else
j+1 < hi && sort!(v, j+1, hi, a, o)
hi = j-1
end
end
return v
end
Random.seed!(1234)
function make_vec(n)
return Random.randperm(Int32(n));
end
@benchmark sort!(arr; alg=QuickSort) setup=(arr=make_vec(1024));
function make_vec(n)
return Random.randperm(n);
end