C++ 线程合并排序速度较慢

标签 c++ algorithm performance sorting

我用 C++ 实现了合并排序算法。
在算法内部,它检查数组的大小是否大于 min_size_to_thread,如果是:则使用线程递归调用该函数。

但是当我增加 min_size_to_thread: 从而减少正在使用的线程数时,该函数会变得更快。即使从 1 个线程变为 2 个线程也是如此。

我的假设是,函数速度会随着线程数量的增加而增加到一定程度,然后又开始下降。这对我来说没有任何意义,所以我开始相信我的实现在某种程度上是错误的。

template <typename T>
void merge_sort(T S[], int S_size, int min_size_to_thread)
{
    if (S_size < 2) return;

    // Left Sequence
    int L_size = S_size / 2;
    T* L = new T[L_size];
    for (int i = 0; i < L_size; i++)
    {
        L[i] = S[i];
    }

    // Right Sequence
    int R_size = (S_size + 1) / 2;
    T* R = new T[R_size];
    for (int i = 0; i < R_size; i++)
    {
        R[i] = S[i + L_size];
    }

    if (S_size > min_size_to_thread)
    {
        std::thread thread_left(merge_sort<T>, L, L_size, min_size_to_thread);
        std::thread thread_right(merge_sort<T>, R, R_size, min_size_to_thread);
        thread_right.join();
        thread_left.join();
    }
    else
    {
        merge_sort<T>(L, L_size, min_size_to_thread);
        merge_sort<T>(R, R_size, min_size_to_thread);
    }

    int S_iterator = 0;
    int L_iterator = 0;
    int R_iterator = 0;

    while ((L_iterator < L_size) && (R_iterator < R_size))
    {
        if (L[L_iterator] < R[R_iterator])
        {
            S[S_iterator] = L[L_iterator];
            ++L_iterator;
        }
        else
        {
            S[S_iterator] = R[R_iterator];
            ++R_iterator;
        }
        ++S_iterator;
    }

    while (L_iterator < L_size)
    {
        S[S_iterator] = L[L_iterator];
        ++L_iterator;
        ++S_iterator;
    }

    while (R_iterator < R_size)
    {
        S[S_iterator] = R[R_iterator];
        ++R_iterator;
        ++S_iterator;
    }

    delete[] L;
    delete[] R;
}

int main()
{
    const int S_size = 500000;
    unsigned char S[S_size];
    for (int i = 0; i < S_size; ++i)
    {
        S[i] = i % 255;
    }

    int min_size_to_thread;

    min_size_to_thread = 250;
    auto t1 = std::chrono::high_resolution_clock::now();
    merge_sort(S, S_size, min_size_to_thread);
    auto t2 = std::chrono::high_resolution_clock::now();
    std::cout << "size > " << min_size_to_thread << ": " << (t2 - t1) / std::chrono::milliseconds(1) << std::endl;

    for (int i = 0; i < S_size; ++i)
    {
        S[i] = i % 255;
    }

    min_size_to_thread = 500;
    t1 = std::chrono::high_resolution_clock::now();
    merge_sort(S, S_size, min_size_to_thread);
    t2 = std::chrono::high_resolution_clock::now();
    std::cout << "size > " << min_size_to_thread << ": " << (t2 - t1) / std::chrono::milliseconds(1) << std::endl;

    for (int i = 0; i < S_size; ++i)
    {
        S[i] = i % 255;
    }

    min_size_to_thread = 1000;
    t1 = std::chrono::high_resolution_clock::now();
    merge_sort(S, S_size, min_size_to_thread);
    t2 = std::chrono::high_resolution_clock::now();
    std::cout << "size > " << min_size_to_thread << ": " << (t2 - t1) / std::chrono::milliseconds(1) << std::endl;

    for (int i = 0; i < S_size; ++i)
    {
        S[i] = i % 255;
    }

    min_size_to_thread = 10000;
    t1 = std::chrono::high_resolution_clock::now();
    merge_sort(S, S_size, min_size_to_thread);
    t2 = std::chrono::high_resolution_clock::now();
    std::cout << "size > " << min_size_to_thread << ": " << (t2 - t1) / std::chrono::milliseconds(1) << std::endl;

    for (int i = 0; i < S_size; ++i)
    {
        S[i] = i % 255;
    }

    min_size_to_thread = 250000;
    t1 = std::chrono::high_resolution_clock::now();
    merge_sort(S, S_size, min_size_to_thread);
    t2 = std::chrono::high_resolution_clock::now();
    std::cout << "size > " << min_size_to_thread << ": " << (t2 - t1) / std::chrono::milliseconds(1) << std::endl;

    for (int i = 0; i < S_size; ++i)
    {
        S[i] = i % 255;
    }

    min_size_to_thread = 500000;
    t1 = std::chrono::high_resolution_clock::now();
    merge_sort(S, S_size, min_size_to_thread);
    t2 = std::chrono::high_resolution_clock::now();
    std::cout << "size > " << min_size_to_thread << ": " << (t2 - t1) / std::chrono::milliseconds(1) << std::endl;

    return 0;
}

enter image description here

最佳答案

我已经编译并运行了您的确切程序,除了添加包含内容之外没有任何修改,结果或多或少符合您的预期:

size > 250: 169
size > 500: 85
size > 1000: 50
size > 10000: 29
size > 250000: 42
size > 500000: 89

根据您的屏幕截图,我推测您正在 Visual Studio 中运行代码。默认运行按钮会将调试器附加到可执行文件并降低运行时性能。相反,请按 Ctrl+F5 在不使用调试器的情况下运行,或者从菜单“调试”->“启动而不调试”。

关于C++ 线程合并排序速度较慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55340043/

相关文章:

c++ - 带有指针、引用、结构和函数的 scanf

c++ - 如何制作可移植且与编译器无关的 glBufferData?

c++ - 指针仍然可以调用成员函数,在它被设置为 NULL 并删除被调用后

根据权重分配的算法,在项目总数未知的情况下,保证良好的分配?

c - 部分或包装乘法 - 谁能识别这个函数?

ruby-on-rails - 优化查询以获得更好的性能

c++ - float 转换 C++

c++ - 在一些容器中处理一个对象

mysql - 查询效率 - 计数

performance - 现代CPU每滴答的缓存带宽