项目优化>C++,concurrentqueue(高性能并发队列)

article/2025/8/23 15:22:37

项目中的数据队列基于轮询和selep的实时性及CUP性能差,需要进行优化,尝试使用concurrentqueue进行优化。网上有一些资料介绍,可供参考。


使用后的个人理解:一个线程安全的queue,并且concurrentqueue的线程安全并不是一味的加锁,它有特殊的技巧,总的来说线程安全且高效但是不保证数据的有序性。是一个很nice的MQ。分析需求,使用阻塞队列,一旦有数据便被读取了,所以使用concurrentqueue可行。
使用

方法功能
ConcurrentQueue(size_t initialSizeEstimate)构造函数,它可选地接受队列将包含的元素数量的估计值
enqueue(T&& item)将一个项目排队,必要时分配额外的空间
try_enqueue(T&& item)将一个项目入队,但前提是已经分配了足够的内存,返回值为bool类型
try_dequeue(T& item)将一个项目出队,如果找到一个项目,则返回true;如果队列为空,则返回false
(size_t size_approx()返回元素个数
方法作用
bool try_dequeue_from_producer(producer_token_t const& producer, U& item)从特定的生产者队列出列
size_t try_dequeue_bulk(consumer_token_t& token, It itemFirst, size_t max)批量出列
bool is_lock_free()检测是否是原子操作

concurrentqueue的API

封装于:“concurrentqueue.h”

# Allocates more memory if necessary
enqueue(item) : bool
enqueue(prod_token, item) : bool
enqueue_bulk(item_first, count) : bool
enqueue_bulk(prod_token, item_first, count) : bool# Fails if not enough memory to enqueue
try_enqueue(item) : bool
try_enqueue(prod_token, item) : bool
try_enqueue_bulk(item_first, count) : bool
try_enqueue_bulk(prod_token, item_first, count) : bool# Attempts to dequeue from the queue (never allocates)
try_dequeue(item&) : bool
try_dequeue(cons_token, item&) : bool
try_dequeue_bulk(item_first, max) : size_t
try_dequeue_bulk(cons_token, item_first, max) : size_t# If you happen to know which producer you want to dequeue from
try_dequeue_from_producer(prod_token, item&) : bool
try_dequeue_bulk_from_producer(prod_token, item_first, max) : size_t# A not-necessarily-accurate count of the total number of elements
size_approx() : size_t

简单示例

#include<iostream>
#include"concurrentqueue.h"
int main()
{int x=0,y=0,z=0;moodycamel::ConcurrentQueue<int> q;q.enqueue(2);q.enqueue(4);q.enqueue(6);q.try_dequeue(x);std::cout << q.size_approx() <<"  "<<x<< std::endl;if (q.is_lock_free)std::cout << "is lok free" << std::endl;return 0;
}
  • 需要注意的是concurrentqueue不保证数据的有序性
#include<iostream>
#include<string>
#include<thread>
#include<mutex>
#include"concurrentqueue.h"class MintorAbstractBuffer
{
public:MintorAbstractBuffer(const uint32_t buffersize):_Buffersize(buffersize){}bool push(std::string s){int32_t size = _buffer.size_approx();if (_Buffersize > size){if (_buffer.enqueue(s)){++_Size;return true;}}return false;}bool RecursivePush(std::string s,int32_t num){//std::lock_guard<std::mutex> lock(_mut);for (int32_t i = 0; i < num; ++i){int32_t size = _buffer.size_approx();if (size >= _Buffersize){std::cout << "Push Error" << " ";return false;}_buffer.enqueue(s);++_Size;}return true;}void pint(){int32_t size = _buffer.size_approx();for (int32_t i = 0; i <= size; ++i){std::string curs;if (!_buffer.try_dequeue(curs))std::cout << "Pint Error" << std::endl;std::cout << curs<< i <<" ";if (!_buffer.enqueue(curs))std::cout << "Pint Error" << std::endl;}std::cout << std::endl;std::cout <<_buffer.size_approx()<< std::endl;std::cout <<_Size<< std::endl;}
private:std::mutex _mut;int32_t _Buffersize;moodycamel::ConcurrentQueue<std::string> _buffer;uint32_t _Size=0;
};int main()
{std::string s1 = "a", s2 = "b", s3 = "c";MintorAbstractBuffer buffer(100000);std::thread t1(&MintorAbstractBuffer::RecursivePush, &buffer, s1, 333);std::thread t2(&MintorAbstractBuffer::RecursivePush, &buffer, s2, 333);std::thread t3(&MintorAbstractBuffer::RecursivePush, &buffer, s3, 334);t1.join();t2.join();t3.join();buffer.pint();return 0;
}

在这里插入图片描述
加锁之后使得++size不会被打断:
在这里插入图片描述
_size是cont的push次数,在++size过程中可能被其他线程的语句终止导致并没有++size,大概是1%的终止率。
想要数据有序还是要使用STL::queue,或者使用ConcurrentQueue的阻塞版本,见文末

#include<iostream>
#include<string>
#include<thread>
#include<mutex>
#include<queue>class MintorAbstractBuffer
{
public:MintorAbstractBuffer(const uint32_t buffersize):_Buffersize(buffersize){}bool push(std::string s){int32_t size = _buffer.size();if (_Buffersize > size){_buffer.push(s);++_Size;return true;}return false;}bool RecursivePush(std::string s,int32_t num){std::lock_guard<std::mutex> lock(_mut);for (int32_t i = 0; i < num; ++i){int32_t size = _buffer.size();if (size > _Buffersize){std::cout << "Push Error" << " ";return false;}_buffer.push(s);++_Size;}return true;}void pint(){int32_t size = _buffer.size();for (int32_t i = 0; i <= size; ++i){std::cout << i;std::cout << _buffer.front() << " ";std::string curs;curs = _buffer.front();_buffer.pop();_buffer.push(curs);}std::cout <<std::endl;std::cout << "push cont :" << _Size << std::endl;std::cout << "_buffer.size() :" << _buffer.size() << std::endl;}private:std::mutex _mut;int32_t _Buffersize;std::queue<std::string> _buffer;uint32_t _Size=0;
};int main()
{std::string s1 = "a", s2 = "b", s3 = "c";MintorAbstractBuffer buffer(100000);int32_t x=3333;std::thread t1(&MintorAbstractBuffer::RecursivePush, &buffer, s1, x);std::thread t2(&MintorAbstractBuffer::RecursivePush, &buffer, s2, x);std::thread t3(&MintorAbstractBuffer::RecursivePush, &buffer, s3, x+1);t1.join();t2.join();t3.join();buffer.pint();return 0;
}

在这里插入图片描述


阻塞版本(blockingconcurrentqueue)的API

封装于:“blockingconcurrentqueue.h”,在工程中使用一个线程不断使用阻塞版本API调用数据可以提升数据的处理速度(缓冲区基本为空)。当然需要知道阻塞与非阻塞队列的区别,下面的API可以通过调整参数来控制多长时间从阻塞的队列中重新获取数据。github上有详细的介绍,出队操作有更改API如下。

wait_dequeue(U& item) : void
wait_dequeue_timed(U& item, std::int64_t timeout_usecs) : bool //时间参数 std::chrono::milliseconds(5)
wait_dequeue_bulk(It itemFirst, size_t max) : size_t 
wait_dequeue_bulk_timed(consumer_token_t& token, It itemFirst, size_t max, std::int64_t timeout_usecs) : size_t 

http://chatgpt.dhexx.cn/article/7hlZLJNV.shtml

相关文章

ConcurrentMap

ConcurrentMap&#xff0c;它是一个接口&#xff0c;是一个能够支持并发访问的java.util.map集合&#xff1b; ConcurrentHashMap是一个线程安全&#xff0c;并且是一个高效的HashMap。 spring 缓存注解 通过查看源代码发现将数据存在ConcurrentMap中 1 Map并发集合 1.1 Co…

学习线程安全队列ConcurrentQueue

首先,基本使用&#xff1a;入队(EnQueue) 、出队(TryDequeue) 、是否为空(IsEmpty)、获取队列内元素数量(Count)。 一、ConcurrentQueue内部结构: 1.实现原理 众所周知&#xff0c;在普通的非线程安全队列有两种实现方式: 1.使用数组实现的循环队列。 2.使用链表实现的队列…

并发系列(六)-----concurrent的简单介绍

一 简介 concurrent包是jdk1.5引入的重要的包&#xff0c;主要代码由大牛Doug Lea完成。这个包下的一些类如果用好了可以很方便的保证数据在多线程下操作的正确性。就比如说线程共享的i&#xff0c;如果使用concurrent包下的Atomic系列类可以很方便的解决这个问题。这篇文章简单…

python并发之concurrent快速入门

导读&#xff1a;我很笨&#xff0c;但是我很快——计算机之所以计算能力如此出众&#xff0c;不在于其有多智能&#xff0c;而是因为它超快的执行速度&#xff0c;而多核心则可以进一步成倍的提高效率。在python中&#xff0c;concurrent库就是用于完成并发的模块之一。 01 初…

Java 并发工具包(concurrent)详解

目录 一、concurrent并发包 二、ReentrantLock&#xff08;可重入锁&#xff09; 1、锁状态中断与可重入 2、尝试非阻塞地获取锁 3、等待可中断 4、设置公平锁 三、CountDownLatch&#xff08;门栓&#xff09; 四、cyclicBarrier&#xff08;栅栏&#xff09; 五、…

JAVA中split函数的用法

JAVA中split函数的用法 只写经常使用的&#xff0c;并不完整。 1.基本用法&#xff0c;将字符串按照指定字符串进行分割&#xff0c;例如&#xff1a; public class Main {public static void main(String[] args) {String ss "abcabcdefg";String[] split ss.sp…

C语言实现split函数

实现类似JAVA编程语言中split函数&#xff1a; &#xff08;这里以空格为分隔符进行演示&#xff09; 函数的声明&#xff1a;void split(char *src,const char *separator,char **dest,int *num) {}变量&#xff1a; 1.*src&#xff1a;要进行分割的字符串地址&#xff0c; 2…

mysql实现自定义split函数

1、自定义split函数脚本 CREATE DEFINER root% FUNCTION tjdemo.fun_get_split_string_total(f_string varchar(1000),f_delimiter varchar(5)) RETURNS int(11) LANGUAGE SQL NOT DETERMINISTIC CONTAINS SQL SQL SECURITY DEFINER COMMENT BEGIN declare returnInt int(11…

Oracle实现split函数

创建TYPE CREATE OR REPLACE TYPE TYPE_SPLIT AS TABLE OF VARCHAR2 (4000);创建函数 CREATE OR REPLACE FUNCTION SPLIT(P_STRING VARCHAR2, P_SEP VARCHAR2 : ,)RETURN TYPE_SPLITPIPELINED ISIDX PLS_INTEGER;V_STRING VARCHAR2(4000) : P_STRING; BEGINLOOPIDX : INSTR(…

java split函数的用法_java中split函数用法以及注意事项

java中split函数用法以及注意事项 发布时间&#xff1a;2020-04-23 10:28:23 来源&#xff1a;亿速云 阅读&#xff1a;215 作者&#xff1a;小新 本篇文章和大家了解一下java中split函数用法以及注意事项。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希…

mysql 创建函数 split_在mysql中实现split函数的几种方法

在mysql中实现split函数的几种方法 关注:98 答案:2 mip版 解决时间 2021-02-07 11:27 提问者夜落花台 2021-02-07 02:11 在mysql中实现split函数的几种方法 最佳答案 二级知识专家蓝莓九栀 2021-02-07 03:28 mysql 5.* 的版本现在没有split 函数,以下是几个自定义的split函数…

Oracle split函数

一、创建split函数 1、创建TYPE CREATE OR REPLACE TYPE TYPE_SPLIT AS TABLE OF VARCHAR2 (4000); / 2、创建split函数 CREATE OR REPLACE FUNCTION SPLIT(P_STRING VARCHAR2, P_SEP VARCHAR2 : ,)RETURN TYPE_SPLITPIPELINED ISIDX PLS_INTEGER;V_STRING VARCHAR2(4000)…

mysql有split函数么_mysql中split函数

在mysql中并没有split函数,需要自己写: 1)获得按指定字符分割的字符串的个数: Sql代码 DELIMITER$$ DROP FUNCTION IFEXISTS`sims`.`func_get_split_string_total`$$ CREATE DEFINER=`root`@`localhost` FUNCTION `func_get_split_string_total`( f_strin 在mysql中并没有sp…

Python之split函数的详解

目录 一、split函数的官方定义 二、split函数的深刻理解 二、split函数的深刻理解 split函数主要应用场景是Python对字符串的处理中&#xff08;数据分析&#xff0c;数据处理&#xff09;&#xff0c;以及计算机二级考试的常考基础知识点。 一、split函数的官方定义 定义…

Python基础之split()函数

一、split()函数描述 split() 通过指定分隔符对字符串进行切片&#xff0c;如果参数 num 有指定值&#xff0c;则分隔 num1 个子字符串split() 方法语法&#xff1a; 二、split()用法 语法&#xff1a; str.split(str"", numstring.count(str)) 参数&#xff1a; str…

分割字符串split函数的正确用法(切片)

分割字符串split函数的正确用法&#xff08;切片&#xff09; split函数是将字符串分割为列表 函数原型&#xff1a; str.split(sep,maxsplit)参数说明&#xff1a; str:表示要进行分割的字符串sep:用于指定分隔符&#xff0c;可以包含多个字符&#xff0c;默认为None,即所有…

PostgreSQL 视图

详细了解视图、函数&#xff08;存储过程&#xff09;、触发器、别名 视图篇 一、视图定义 引言: 假设天气记录和城市为止的组合列表对我们的应用有用&#xff0c;但我 们又不想每次需要使用它时都敲入整个查询。我们可以在该查询上创建一个视图&#xff0c;这会给该 查询一…

SQL Server 数据库之视图(二)

视图&#xff08;二&#xff09; 1. 查询视图信息1.1 查询和视图设计工具1.2 关系图视图1.3 条件窗格1.4 SQL 窗格1.5 结果窗格1.6 SQL 编辑器1.7 获取有关视图的信息 2. 创建基于视图的视图3. 删除视图 1. 查询视图信息 1.1 查询和视图设计工具 打开视图的定义、显示查询视图…

hive视图

Hive的视图 应用场景将特定的列提供给用户&#xff0c;保护数据隐私 用于查询语句复杂的场景 通过隐藏子查询、连接和函数来简化查询的逻辑结构只保存定义&#xff0c;不存储数据 如果删除或更改基础表&#xff0c;则查询视图将失败 视图是只读的&#xff0c;不能插入或装载数据…

mysql 查询视图_MySQL查看视图

查看视图 是指查看数据库中&#xff0c;已经存在的视图的定义 查看视图&#xff0c;必须要有SHOW VIEW的权限 查看视图有三种方式 DESCRIBE语句 使用DESCRIBE语句&#xff0c;查看视图 MySQL中&#xff0c;使用DESCRIBE可以查看视图的字段信息&#xff0c;其中&#xff0c;包括…