初探:c++异步编程之std::promise和std::future【异步数据获取】

news2024/12/25 1:29:54

c++异步编程之std::promise和std::future

  • 1.std::future获取std::asnyc结果
  • 2.模拟一个异步函数接口
    • i.模拟一个客户端类包含异步请求接口
    • ii.调用异步接口获取结果

c11以后标准库提供了thread,说起异步可能会第一时间想起thread,线程确实好东西,不过使用线程需要很注意数据同步问题。当然了线程也不能把线程执行结果返回回来,一般都是需要使用全局变量来做数据同步。今天要探讨的是另外一些异步方式如:std::async 、std::packaged_task ,配合以std::promise和std::future来获取执行结果,使用起来有很不错的疗效。

1.std::future获取std::asnyc结果

// 模拟耗时任务
std::string sendRequest()
{
	// 休眠模拟耗时操作3s
	std::this_thread::sleep_for(std::chrono::seconds(3));
	return "good boy";
}

int main(int argc, char* argv[])
{
	// 启动异步任务并获取future
	std::future<std::string> result_future = std::async(std::launch::async, sendRequest);

	std::cout << "doing something ...\n";

	// 获取结果,调用get会阻塞直到结果可用
	std::string result = result_future.get();
	std::cout << "get a result: " << result << std::endl;

	char ch = 0;
	while (std::cin >> ch)
	{
		if (ch == 'q')
		{
			std::cout << "pressed 'q' exit ...\n";
			break;
		}
		std::this_thread::sleep_for(std::chrono::microseconds(10));
	}

	return 0;
}

也可以先调用wait等待结果可用再去获取结果, 这里调用get相当于先调用了wait和get结果获取。
在这里插入图片描述

2.模拟一个异步函数接口

i.模拟一个客户端类包含异步请求接口

namespace AClient
{
	struct Position
	{
		float x;
		float y;
		float z;
	};

	struct Request
	{
		// 唯一的一个id
		uint64_t uid;
		std::string params;
	};

	struct Response
	{
		int status;
		Position pos;
	};

	using SharedRequest = std::shared_ptr<Request>;
	using SharedResponse = std::shared_ptr<Response>;

	using Promise = std::promise<SharedResponse>;
	using SharePromise = std::shared_ptr<Promise>;
	using SharedFuture = std::shared_future<SharedResponse>;

	using CallbackType = std::function<void(SharedFuture)>;

	class AsyncRequestClient
	{
	public:
		AsyncRequestClient() = default;
		virtual ~AsyncRequestClient() = default;

		static inline char* getLocalTime()
		{
			static char local[26] = { 0 };
			SYSTEMTIME wtm;
			struct tm tm;

			GetLocalTime(&wtm);
			tm.tm_year = wtm.wYear - 1900;
			tm.tm_mon = wtm.wMonth - 1;
			tm.tm_mday = wtm.wDay;
			tm.tm_hour = wtm.wHour;
			tm.tm_min = wtm.wMinute;
			tm.tm_sec = wtm.wSecond;
			tm.tm_isdst = -1;

			strftime(local, 26, "%Y-%m-%d %H:%M:%S", &tm);

			return local;
		}

		void sendRequest(SharedRequest request)
		{
			std::thread req_thread([request, this] {
				std::this_thread::sleep_for(std::chrono::seconds(3));

				// 假设这里通过远程调用解析得到了数据
				SharedResponse _response = std::make_shared<Response>();
				_response->status = 1;
				_response->pos.x = 1.234567;
				_response->pos.y = 3.141592;
				_response->pos.z = 1.0f;

				std::cout << "Time:[" << getLocalTime() << "] tid:" << std::this_thread::get_id() << " ,request id:" << request->uid << " get resonse." << std::endl;

				std::unique_lock<std::mutex> lck(mutex_);
				if (this->request_list_.count(request->uid) == 0)
				{
					std::cout << "Invalid request id, return." << std::endl;
					return;
				}

				auto req_tuple = this->request_list_[request->uid];
				auto promise = std::get<0>(req_tuple);
				auto callback = std::get<1>(req_tuple);
				auto future = std::get<2>(req_tuple);

				this->request_list_.erase(request->uid);
				lck.unlock();

				promise->set_value(_response);
				callback(future);
			});
			req_thread.detach();
		}

		template<typename CallbackT>
		SharedFuture asyncRequest(SharedRequest request, CallbackT&& cb)
		{
			std::lock_guard<std::mutex> lock(mutex_);
			std::cout << "Time:[" << getLocalTime() << "] tid:" << std::this_thread::get_id() << request->uid << " ,send async request." << std::endl;

			SharePromise promise = std::make_shared<Promise>();
			SharedFuture future(promise->get_future());

			this->request_list_[request->uid] = std::make_tuple(promise, std::forward<CallbackType>(cb), future);

			// 此处只简单的用一个线程来模拟调用服务过程(实际可能是TCP、IPC、RPC)
			sendRequest(request);

			return future;
		}
	private:
		std::map<uint64_t, std::tuple<SharePromise, CallbackType, SharedFuture>> request_list_;
		std::mutex mutex_;
	};
}

ii.调用异步接口获取结果

int main(int argc, char* argv[])
{
	auto request = std::make_shared<AClient::Request>();
	request->uid = 10086;
	request->params = "{\"timestamp\": 1678222981}";

	// 开始异步调用
	AClient::AsyncRequestClient client;
	auto future_result = client.asyncRequest(request, [](AClient::SharedFuture future) {
		auto response = future.get();
		//std::cout << "Time:[" << AClient::AsyncRequestClient::getLocalTime() << "] tid:" << 		std::this_thread::get_id() << ",resonse status:" << response->status
		//			<< ",x:" << response->pos.x << ",y:" << response->pos.y << ",z:" << response->pos.z << std::endl;
	});

	// 等待结果
	future_result.wait();
	std::cout << "Time:[" << ASYClient::AsyncRequestClient::getLocalTime() << "] tid:" <<      std::this_thread::get_id() << " ,wait a result " << "status:" << future_result.get()->status
		<< ",x: " << future_result.get()->pos.x << ",y: " << future_result.get()->pos.y << ",z: " << future_result.get()->pos.z << std::endl;
	char ch = 0;
	while (std::cin >> ch)
	{
		if (ch == 'q')
		{
			std::cout << "pressed 'q' exit ...\n";
			break;
		}
		std::this_thread::sleep_for(std::chrono::microseconds(10));
	}

	return 0;
}

在这里插入图片描述
可以看到我们的调用过程和回调过程是在2个不同的线程, 耗时操作同样是用3秒休眠来代替。显而易见是调用3秒后得到了结果。上面例程获取结果有2种方式:1.通过future 等待结果 2.通过回调函数获取。

作者:费码程序猿
欢迎技术交流:QQ:255895056
转载请注明出处,如有不当欢迎指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054931.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023年人均GDP百强市分布图

2023年人均GDP百强市分布图

redis安装,redis的数据类型和使用场景,Redis事务,Redis持久化,Redis淘汰策略

Redis简介 https://redis.io/docs/data-types/ Redis&#xff08;Remote Dictionary Server )远程字典服务&#xff0c;是一个开源的使用ANSI C语言编写、支持网络、可基于内存也可持久化的日志型、Key-Value(NoSQL)数据库。 Redis的特点 性能极高&#xff0c;基于内存&…

ORACLE ADG 主库的归档日志不能主动传递到备库

主库有三个节点 &#xff0c;其中两个节点传递没有问题&#xff0c;唯独节点二的归档日志不能主动传递到备库&#xff0c;都是在备库恢复需要的时候一个个传递到备库。下面是备库的日志。 Media Recovery Waiting for thread 2 sequence 1204582 …

SAP和致远OA系统集成案例

一、项目介绍 重庆某控股&#xff08;集团&#xff09;有限公司是一家集合汽柴油动力及终端、摩托车、储能电源、汽车零部件、金融服务等产业的多元化集团公司&#xff0c;业务遍布全球80多个国家及地区&#xff0c;2021年营业收入达80亿元。 为推动集团信息化、数字化转型…

基于WonderJourney生成电影级连续的3D场景视频

在本文中,我将详细记录在Windows环境下配置和使用WonderJourney项目的完整流程,包括环境搭建、常见问题的解决方案以及如何修改源码以兼容Windows系统。WonderJourney项目能够生成高度逼真的村庄视频,并允许用户通过配置文件对视频生成过程进行精细化控制。 由于官方文档在…

选型指南:CNAPP能力成熟度评估Checklist

随着云计算服务大量使用&#xff0c;网络攻击面的不断扩大&#xff0c;那些过去为传统数据中心而设计的安全工具和运营流程将很难应对云端的安全威胁。相比过去&#xff0c;安全团队现在面临超过10到100倍的容器化保护需求&#xff0c;大量的动态云资产需要追踪&#xff0c;同时…

MySQL 在 Windows 和 Ubuntu 上的安装与远程连接配置简介

MySQL 是一个广泛使用的开源关系型数据库管理系统&#xff0c;它提供了多用户、多线程的数据库服务。本文将介绍如何在 Windows 和 Ubuntu 操作系统上安装 MySQL&#xff0c;并配置远程连接。 Windows 上的 MySQL 安装 1. 下载 MySQL Installer 访问 MySQL 官方网站下载 Win…

c++--类(上)

C之类&#xff08;上&#xff09; 一、类的定义1.1 类定义格式1.2 访问限定符1.3 类域 二、实例化2.1 实例化的概念2.2 对象大小 三、this指针 一、类的定义 1.1 类定义格式 1、class为定义类的关键字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略…

Ollama - Llama3 docker版本安装部署使用

项目地址&#xff1a;https://github.com/meta-llama/llama3 Meta 发布两款开源Llama 3 8B与Llama 3 70B模型&#xff0c;供外部开发者免费使用。Llama 3的这两个版本&#xff0c;也将很快登陆主要的云供应商。 按照Meta的说法&#xff0c;Llama 3 8B和Llama 3 70B是目前同体量…

threejs中实现物体阴影

在Three.js中实现阴影需要几个步骤&#xff0c;包括设置渲染器、光源以及物体的材质等。以下是一个基本的实现阴影的步骤&#xff1a; 1、设置渲染器以支持阴影&#xff1a; const renderer new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerH…

三大运营管理平台:打造智能化新能源数据管理的核心利器

随着全球能源结构的转型和新能源技术的快速发展&#xff0c;智能化新能源数据管理成为行业发展的关键。三大运营管理平台的出现&#xff0c;正是为了解决这一需求&#xff0c;它们通过整合先进的信息技术和智能算法&#xff0c;为新能源企业提供了全面、高效、精准的数据管理解…

告别帕金森手抖,这些维生素是你的秘密武器!

亲们&#xff0c;你们有没有遇到过这样的情况&#xff1f;家里的长辈或是自己&#xff0c;偶尔会出现手不自觉颤抖的现象&#xff0c;特别是被诊断为帕金森病的朋友&#xff0c;更是深受其扰。&#x1f614; 别担心&#xff0c;今天就来聊聊如何通过科学补充一些关键维生素&…

函数:02

1.三角函数 名称表达式正弦sinx b r \frac{b}{r} rb​余弦cosx a r \frac{a}{r} ra​正切tanx b a \frac{b}{a} ab​余切cotx a b \frac{a}{b} ba​正割secx r a \frac{r}{a} ar​余割cotx r b \frac{r}{b} br​ 1.1用正弦&#xff0c;余弦函数表示正/余切&#xff0c;正/余割…

Web大学生网页作业成品——保护环境环保介绍网页设计与实现(HTML+CSS)(1个页面)

&#x1f389;&#x1f389;&#x1f389; 常见网页设计作业题材有**汽车、环保、明星、文化、国家、抗疫、景点、人物、体育、植物、公益、图书、节日、游戏、商城、旅游、家乡、学校、电影、动漫、非遗、动物、个人、企业、美食、婚纱、其他**等网页设计题目, 可满足大学生网…

20221元组

在Python语言中, (7)是一种可变的、有序的序列结构,其中元素可以重复。 A.元组(tuple) B. 字符串(str) C. 列表(list) D.集合(set) ChatGPT 说&#xff1a; ChatGPT 在Python中&#xff0c;选项 C 列表(list) 符合题目描述。 解释&#xff1a; 列表 (list) 是一种可变的、有…

OOP篇(Java - 思维逻辑练习)(doing)

目录 一、继承 1. 简介 2. 表现形式 2.1. 电脑的表现形式 2.2. 程序的表现形式 资料库 课程 课程放入到资料库 视频资源 资源库 存在问题 如何解决问题 3. 继承 定义父类 课程类继承 视频类继承item 资源库类2 整个的继承关系 4. 通过继承得到了什么&#x…

基于spring boot的酒店管理系统

获取源码联系方式请查看文章结尾&#x1f345; 目 录 基于spying boot的酒店管理系统 ABSTRACT 第一章 绪论 1.1课题背景 1.2研究意义 1.3研究内容 第二章 技术介绍 2.1相关技术 2.2java技术 2.3MySQL数据库 2.4 Tomcat介绍 2.5 SSM框架 第3章 需求分析 3.1需求分…

水文仪器设备

水文仪器设备可以监测水位、雨量、流速、流量等水文要素。这些设备使用各种传感技术和测量原理来获取准确的数据。以下是常见的水文仪器设备&#xff1a; 水位计&#xff1a;用来测量水位高度的仪器。常见的水位计有浮标式水位计、压力式水位计、超声波水位计等。 雨量计&…

Redis大显身手:实时用户活跃排行榜

文章目录 场景说明方案设计数据结构 Redis使用方案排行榜实现更新用户活跃积分幂等策略榜单评分更新触发活跃度更新排行榜查询 技术派项目源码地址 : Gitee :技术派 - https://gitee.com/itwanger/paicodingGithub :技术派 - https://github.com/itwanger/paicoding 效果如图 …

maven项目的目录结构

今天用jdk17创建maven项目时候出的问题 那就一步步自己整了 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schema…