为什么Boost';与Julia';什么是快速排序? < >我比较了朱丽亚和C++之间的性能。然后我发现Julia中的快速排序速度要快得多(甚至比C++还要快),特别是当数组的大小非常大时

为什么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-

有人能解释一下原因吗

快速排序.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-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的排序在运行时性能上相当接近
  • 我还测试了C的
    qsort
    ,后者速度较慢。这就是为什么我不再进一步展示它的原因
  • 我还使用BenchmarkTools Julia包对Julia的排序进行基准测试
  • 绘图说明:

    • 我使用脚本进行绘图
    • 如果标签太小:
      • 蓝色/最快:boost的类型
      • 绿色和红色:
        std::sort
        和Julia
    标杆管理 C++

    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