C++链表并行排序实现(利用std::future)

文章展示了如何使用C++实现快速排序算法,首先是一个串行版本,然后是一个利用std::async进行并行处理的版本,尝试通过多线程提升排序效率。尽管std::async可能在任务过多时转为同步执行,但提出了自定义spawn_task函数以及使用线程池来优化的可能性。
摘要由CSDN通过智能技术生成

串行的链表排序

template<typename T>
std::list<T> quick_sort(std::list<T> input) {
    if (input.empty()) return input;
    std::list<T> result;
    // 基准元素放入result中
    result.splice(result.begin(), input, input.begin());
    // 避免遍历链表 我们取首元素作为基准元素
    T const& pivot = *result.begin();
    // 返回指向>=基准元素的第一个元素 【input.begin(), divide_point, input.end()】
    auto divide_point = std::partition(input.begin(), input.end(), [&](T const& t) {
        return t < pivot;
    });
    std::list<T> lower_part;
    // 【input.begin(), divide_point)移动到lower_part末尾
    // 将 input 中从开头到 divide_point 之前的元素移动到 lower_part 的末尾
    lower_part.splice(lower_part.end(), input, input.begin(), divide_point);

    // Move传入避免拷贝  结果隐式移动方式向外返回
    auto new_lower(quick_sort(std::move(lower_part)));
    auto new_higher(quick_sort(std::move(input)));

    // 注意 基准元素之前已经放在result中
    // new_higher所含元素放在基准元素之后
    result.splice(result.end(), new_higher);
    // new_lower 放在基准元素之前
    result.splice(result.begin(), new_lower);

    return result;
}

int main() {
    std::list<int> input = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    auto result = quick_sort(std::move(input));
    for (auto it = result.begin(); it != result.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    return 0;
}

运用future实现并行快速排序

#include <iostream>
#include <future>
#include <vector>
#include <numeric>
#include <chrono>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <list>

template<typename T>
std::list<T> parallel_quick_sort(std::list<T> input) {
    if (input.empty()) return input;
    std::list<T> result;
    // 基准元素放入result中
    result.splice(result.begin(), input, input.begin());
    // 避免遍历链表 我们取首元素作为基准元素
    T const& pivot = *result.begin();
    // 返回指向>=基准元素的第一个元素 【input.begin(), divide_point, input.end()】
    auto divide_point = std::partition(input.begin(), input.end(), [&](T const& t) {
        return t < pivot;
    });
    std::list<T> lower_part;
    // 【input.begin(), divide_point)移动到lower_part末尾
    // 将 input 中从开头到 divide_point 之前的元素移动到 lower_part 的末尾
    lower_part.splice(lower_part.end(), input, input.begin(), divide_point);

    // Move传入避免拷贝  结果隐式移动方式向外返回
    std::future<std::list<T>> new_lower(std::async(&parallel_quick_sort<T>, std::move(lower_part)));
    auto new_higher(parallel_quick_sort(std::move(input)));

    // 注意 基准元素之前已经放在result中
    // new_higher所含元素放在基准元素之后
    result.splice(result.end(), new_higher);
    // new_lower 放在基准元素之前
    result.splice(result.begin(), new_lower.get());

    return result;
}

int main() {
    std::list<int> input = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};
    auto result = parallel_quick_sort(std::move(input));
    for (auto it = result.begin(); it != result.end(); ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;
    return 0;
}

代码中,链表的前半部分的排序不再由当前线程执行,而是通过std::async()在另一个线程上操作。

然后递归调用parallel_quick_sort,并发生成多个线程,线程数=2^递归层数

注意,一旦线程库判断任务过多,std::async()的实现可能并不是在新线程上操作,而是按照同步方式生成新任务,从而减小开销。

std::partition操作耗时比较长,它是串行调用的,所以上述代码仍然有上升空间。

除了使用std::async外,可以自己实现一下spawn_task函数,包装下std::packaged_task和std::thread。

使用 std::invoke_result_t 可以更清晰地表达函数对象的返回类型,避免了使用 std::result_of 时可能出现的模板参数推导问题。

template<typename F, typename A>
std::future<std::invoke_result_t<F, A>> spawn_task(F&& f, A&& a) {
    using result_type = std::invoke_result_t<F, A>;
    std::packaged_task<result_type(A&&)> task(std::move(f));
    std::future<result_type> res(task.get_future());
    std::thread t(std::move(task), std::move(a));
    t.detach();
    return res;
}

可以顺着这个思路升级到复杂的实现:向队列中添加任务,由线程池中的工作线程负责运行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拾牙慧者

欢迎请作者喝奶茶

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值