thread_pool的一些想法

2024-06-01 03:12
文章标签 thread 想法 pool

本文主要是介绍thread_pool的一些想法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前有探讨过线程池的逻辑,这两天刚好闲下来,看了github上C++20的句法,语法是有点夸张,

以这个push为例:

template<typename F, typename... Args>requires std::invocable<F, Args...>
inline std::future<std::invoke_result_t<F, Args...>> push(F&& f, Args&&... args)
{// std::packaged_task is used to get a future out of the function call.auto pck = std::make_shared<std::packaged_task<std::invoke_result_t<F, Args...>()>>(// This has been tested to ensure perfect forwarding still occurs with// the parameters captured by reference.[&f, &args...]{if constexpr (sizeof...(args) == 0){// Only need to forward the function.return std::forward<F>(f);}else{// std::forward is used to ensure perfect//     forwarding of rvalues where necessary.// std::bind is used to make a parameterless function//     that simulates calling f with its respective arguments.return std::bind(std::forward<F>(f), std::forward<Args>(args)...);}}());// Lastly, create a function that wraps the packaged// task into a signature of void().this->tasks.push(std::make_unique<std::function<void()>>([pck] { (*pck)(); }));// Notify one waiting thread so it can wake up and take this new task.std::lock_guard lock(this->signal_mut);this->signal.notify_one();// Return the future, the user is now responsible// for the return value of the task.return pck->get_future();
}

这段代码是C++20标准中使用的概念(concepts)和协程(coroutines)的一部分,用于创建一个异步执行函数并返回其结果的std::future

  1. 概念定义(Concept Definition):

    template<typename F, typename... Args> concept Invocable = std::invocable<F, Args...>;

    这里定义了一个名为Invocable的概念。std::invocable是一个C++标准库中的类型特征,用于检查给定的类型F是否可以使用参数Args...进行调用。如果F可以被调用,那么Invocable概念就是有效的。当前程序中没有自己定义concept,而是直接使用了std定义的invocable

  2. 模板函数定义:

    template<typename F, typename... Args> requires std::invocable<F, Args...> std::future<std::invoke_result_t<F, Args...>> push(F&& f, Args&&... args)

    定义了一个模板函数myFunction,它接受一个可调用对象F和任意数量的参数Args...。函数的返回类型是一个std::future,其模板参数std::invoke_result_t<F, Args...>F调用Args...后返回的类型。

    requires std::invocable<F, Args...>是一个约束,它要求FArgs...必须满足std::invocable概念,即F必须能够被调用,并且其参数类型必须是Args...

  3. 创建std::packaged_task对象:

		auto pck = std::make_shared<std::packaged_task<std::invoke_result_t<F, Args...>()>>(// This has been tested to ensure perfect forwarding still occurs with// the parameters captured by reference.[&f, &args...]{if constexpr (sizeof...(args) == 0){// Only need to forward the function.return std::forward<F>(f);}else{// std::forward is used to ensure perfect//     forwarding of rvalues where necessary.// std::bind is used to make a parameterless function//     that simulates calling f with its respective arguments.return std::bind(std::forward<F>(f), std::forward<Args>(args)...);}}());

这里创建了一个std::packaged_task对象的共享指针pckstd::packaged_task是一个封装了可调用对象和其参数的类,它可以被用来生成std::future对象。

构造函数中的lambda表达式是一个函数对象,它根据参数的数量来决定如何调用F。如果Args...为空,则直接返回std::forward<F>(f);否则,使用std::bind来绑定fargs...

4. 返回std::future:

return pck->get_future();

最后,函数返回pck对象的get_future()方法的结果,这是一个std::future对象,它将与std::packaged_task对象关联,允许异步访问F调用的结果。

整体逻辑:

就是把各种类型,各种参数的函数封装成对象,然后像普通数据一样传递到列表中,线程池按一定规则获取这些对象执行,完成后发起线程再获取返回数据。

应用:

有了这个东西,C++编写行情服务器的难度将由地狱级一下上升为玩具级,所有的数据处理函数放在队列中,然后线程池按规则将这些队列执行,将数据带给各自的发起处。这些队列中,有些是专门进行常规数据处理的,有些则是响应用户请求,还有的则是可能查看用户权限什么的,全部可以拆分开来扔到队列中,由线程池并行执行,若需要有先后顺序的,加上一定编号和优先级即可。

如此的行情服务器即规范又可以发挥出CPU的最大性能。

拓展:

线程池一般分两种,当前讨论的属于消费--生产者模式,即用户请求,数据处理这些都属于生产端,线程池则属于消费端,适合处理高并发,低数据传输的。若产生的数据非常巨大,则可以换一种线程池模型,这种模型有三种不同属性,同一时刻系统中只有一个领导者,由它来进行调度,他会先选择好继任者后进入工作者模式,并完成自己的工作,而原先的继任者则成为领导者,接替原先领导者的一切工作。好处是数据无需在线程中传递,难点是各线程状态的切换。后面有时间应想办法实现这个线程池模式,看起来这种线程池做行情服务器更加高效。

这篇关于thread_pool的一些想法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1019827

相关文章

Thread如何划分为Warp?

1 .Thread如何划分为Warp? https://jielahou.com/code/cuda/thread-to-warp.html  Thread Index和Thread ID之间有什么关系呢?(线程架构参考这里:CUDA C++ Programming Guide (nvidia.com)open in new window) 1维的Thread Index,其Thread

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本  1.2 认识Nano版本 2 STM32F446U上移植RT-Thread  2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet  2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码  2.2.3.

关于并发的一些想法

1.多个用户同时访问一个网站系统是并发,也会造成并发问题(但这个问题不是线程间的并发问题,不是对临界变量的并发问题。这个很容易混淆的)。这里造成的并发的问题是由于用户过多发出的http的请求过多,程序排队处理这些请求,同时,对于同一个数据库和同一tomcat来承受这些请求(可能千万个请求),同时服务器的cpu和内存等都会有问题,必然导致用户响应界面效果不好,产生卡顿现象。因此,才有了分布式、集群、

sobel_dir 方向图和sobel的一些想法

怎么使用呢! 1,通过方向图可以提取 直线 或水平线region区域,提出来的dirregion区域 2,通过sobel的幅度度,分割出变化剧烈的区域 fuduregion 3,两个region相交,可以准确定位幅度范围内+方向的边界 4,sobel算子是可以只做x,y方向的单项幅度图的,sobel_amp在一定场合有特别的用处,值得关注 5,关于大掩码超过3的size,要注意的

GTK中创建线程函数g_thread_new和g_thread_create的区别

使用GThread函数,需要引用glib.h头文件。 这两个接口的核心区别就是  g_thread_create 是旧的接口,现在已经不使用了,而g_thread_new是新的接口,建议使用。 g_thread_create: g_thread_create has been deprecated since version 2.32 and should not be used in n

基于 rt-thread的I2C操作EEPROM(AT24C02)

一、AT24C02 The AT24C01A/02/04/08A/16A provides 1024/2048/4096/8192/16384 bits of serial electrically erasable and programmable read-only memory (EEPROM) organized as 128/256/512/1024/2048 words of 8 b

[项目][CMP][Thread Cache]详细讲解

目录 1.设计&结构2.申请内存3.释放内存4.框架 1.设计&结构 Thread Cache是哈希桶结构,每个桶是一个按桶位置映射大小的内存块对象的自由链表 每个线程都会有一个Thread Cache对象,这样每个线程在这里获取对象和释放对象时是无锁的 TLS – Thread Local Strorage Linux gcc下TLSWindows vs下TLS

线程池工具类——Thread学习笔记

记录一下线程池工具类: /*** 线程池工具类* @author lixiang* @date 2018年10月10日 - 11:10* @history 2018年10月10日 - 11:10 lixiang create.*/public class ThreadPoolHelper {private static final Logger logger = LoggerFactory.g

模拟线程死锁——Thread学习笔记

记录一下之前写过的一段模拟死锁的代码: /*** 模拟死锁** @author lixiang* @date 2018年10月12日 - 9:51* @history 2018年10月12日 - 9:51 lixiang create.*/public class HoldLockDemo {private static Object[] lock = new Object[10];priv

python测试开发基础---multiprocessing.Pool

1. 基础概念 多进程编程:Python中的multiprocessing模块允许你使用多个进程并行执行任务,这可以提高程序的性能,尤其是在需要大量计算的情况下。Pool类是一个常用工具,可以帮助你更轻松地管理多个进程。 进程池:进程池是一个包含多个工作进程的池子,用来处理多个任务。你可以将任务分配给池中的进程,池会自动管理这些进程。 2. 使用方法 以下是multiprocessing.