51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

C++ std::async 工具

在 C++11 中,std::async 是一个非常有用的标准库功能,它不仅可以用来执行 异步任务 ,即在后台线程中执行某些操作,同时也可以用于 延迟任务,即任务只有在需要结果时才会执行。


  • 异步任务:可以并发执行的任务,它们之间相互独立,不需要等待彼此完成。异步任务适合计算量较大、耗时较长的任务,比如大规模数据处理、复杂的数学计算等任务。
  • 延迟任务:任务的执行被推迟,直到真正需要结果时才开始执行。延迟任务适合一些需要推迟执行的业务场景,比如:系统负载较高、结果又不急需,提升系统性能。
  1. 异步任务 {#title-0} ==================

1.1 异步任务的基本使用 {#title-1}

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>


int task(int number)
{
	std::this_thread::sleep_for(std::chrono::seconds(2));
	return 100 + number;
}


void test()
{
	// 下面代码执行完成之后,线程函数就开始执行
	std::future<int> fut = std::async(std::launch::async, task, 10);
	std::cout << "任务开始执行..." << std::endl;

	try
	{
		// 阻塞等待任务函数执行结束,并得到结果
		int ret = fut.get();
		std::cout << "ret = " << ret << std::endl;
	}
	catch (const std::exception& ex)
	{
		std::cout << ex.what() << std::endl;
	}

	std::cout << "程序结束" << std::endl;
}


int main()
{
	test();
	return EXIT_SUCCESS;
}
#endif

1.2 非阻塞获得任务结果 {#title-2}

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>


// 2. 非阻塞方式获得异步任务结果
// wait_for 等待指定长度的时间,返回任务状态:ready、timeout
// wait_until 等待到某个时间点,返回任务状态:ready、timeout
// 例如:等待一段时间后,没有拿到结果,此时可以进行其他的操作。

int calculate(int number)
{
	int result = 0;
	for (int i = 0; i < number; ++i)
	{
		std::this_thread::sleep_for(std::chrono::seconds(1));
		result += 10;
	}

	return result;
}


void test()
{
	std::future<int> fut = std::async(std::launch::async, calculate, 5);
	std::cout << "任务开始执行..." << std::endl;


	while (true)
	{
		std::future_status status = fut.wait_for(std::chrono::seconds(1));
		if (status == std::future_status::ready)
		{
			std::cout << "子线程结果:" << fut.get() << std::endl;
			break;
		}

		if (status == std::future_status::timeout)
		{
			std::cout << "子任务尚未执行完毕,做会其他的事情..." << std::endl;
		}
	}
}


int main()
{
	test();
	return EXIT_SUCCESS;
}
#endif

1.3 没有返回值任务场景 {#title-3}

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>
#include<fstream>


// wait 阻塞等待任务函数执行结束,并不关心返回值。例如,AB两个线程执行完毕后,将结果写入到文件中,后续由主线程进行文件合并。
void write_file(std::string filename, std::string content)
{
	std::ofstream ofs(filename);

	// 等待 2 秒,表示耗时任务
	std::this_thread::sleep_for(std::chrono::seconds(2));

	ofs << content << std::endl;
	ofs.close();
}


void test()
{
	// 下面代码执行完成之后,线程函数就开始执行
	std::future<void> fut1 = std::async(std::launch::async, write_file, "demo1.txt", "hello world");
	std::future<void> fut2 = std::async(std::launch::async, write_file, "demo2.txt", "hello python");
	std::cout << "任务开始执行..." << std::endl;

	// 等待异步任务执行完毕
	fut1.wait();
	fut2.wait();

	// 合并文件
	std::ifstream ifs1("demo1.txt");
	std::ifstream ifs2("demo2.txt");
	std::ofstream ofs("demo.txt");

	std::copy(std::istreambuf_iterator<char>(ifs1), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(ofs));
	std::copy(std::istreambuf_iterator<char>(ifs2), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(ofs));

	ifs1.close();
	ifs2.close();
	ofs.close();

	std::cout << "程序结束" << std::endl;
}


int main()
{
	test();
	return EXIT_SUCCESS;
}
#endif
  1. 延迟任务 {#title-4} ==================

2.1 延迟任务的基本使用 {#title-5}


2.2 独享和共享任务结果 {#title-6}


2.3 延迟任务的案例理解 {#title-7}

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<thread>
#include<chrono>
#include<future>
#include<map>


// 1. 延迟任务创建和执行
void test01()
{

	size_t timeout = 2;
	std::future<int> fut = std::async(std::launch::deferred, [&timeout](int number) {
		
		std::cout << "延迟任务开始执行..." << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(timeout));
		return 100 + number;

	}, 10);

	// get、wait 调用时,将会触发线程函数执行
	int ret = fut.get();
	// std::cout << "ret = " << ret << std::endl;
	// fut.wait();

	// wait_for、wait_until 无法触发线程函数运行,可用来查询任务状态
	// deferred 任务尚未开始执行
	// timeout 任务正在执行
	// ready 任务处理完毕
	// fut.wait_for(std::chrono::seconds(2));
	// fut.wait_until(std::chrono::steady_clock().now() + std::chrono::seconds(2));
}

// 2. std::shared_future
void test02()
{
	std::future<int> fut = std::async(std::launch::deferred, []() {
		std::cout << "延迟任务开始执行..." << std::endl;
		std::this_thread::sleep_for(std::chrono::seconds(2));
		return 100;
	});

#if 0
	// std::future 只能获取一次结果,重复获取结果将会抛出异常
	// std::shared_future 可以重复获取结果
	int ret = fut.get();
	ret = fut.get();
#else
	// 解决该问题:可以使用 std::shared_future 代替 std::future
	// 可以将 std::future 转换为 std::shared_future,此时 fut 将变得无效
	// 注意:不要先对 std::future 调用 get 之后,再进行类型转换,否则得到的 std::shared_future 也是不可用
	// 也可以在创建任务时候,直接指定 std::shared_future 类型承接返回值
	// 即:std::future<int> fut = std::async(...)
	
	std::shared_future<int> shared_fut = fut.share();
	int ret = shared_fut.get();
	ret = shared_fut.get();
#endif
}


// 3. 延迟任务的案例
// 假设:用户在网页查看某张图片,但是只有处理过的图片才能够展示给用户
// 我们可以:
// 1. 集中时间处理所有图片,这样的话,会在一段时间时间内占用大量的系统资源,会影响系统性能
// 2. 按需处理图片,用户请求那张就开个线程处理哪张,处理过的图像直接返回,剩余未处理的可以在系统空闲时再集中处理
// 显然,在系统资源有限的情况下,第二种更合适一些。第二种就需要用到延时任务。

std::string data_analysis(std::string path)
{
	std::this_thread::sleep_for(std::chrono::seconds(10));
	return path;
}

void test03()
{
	std::map<std::string, std::shared_future<std::string>> tasks;

	// 添加延迟图像处理任务
	tasks.insert({ "a.png", std::async(std::launch::deferred, data_analysis, "a.png")});
	tasks.insert({ "b.png", std::async(std::launch::deferred, data_analysis, "b.png")});
	tasks.insert({ "c.png", std::async(std::launch::deferred, data_analysis, "c.png")});

	// 用户查看图像
	std::string picture;
	while (true)
	{
		std::cout << "请输入查看的图像:";
		std::cin >> picture;

		// 查看图像目前状态
		std::shared_future<std::string>& fut = tasks[picture];
		std::future_status status = fut.wait_for(std::chrono::seconds(1));

		if (status == std::future_status::deferred)
		{
			if (status != std::future_status::timeout)
			{
				std::cout << "图像尚未处理, 开始处理图像..." << std::endl;
				std::thread([&fut]() { fut.wait(); }).detach();
			}
		}

		if (status == std::future_status::timeout)
		{
			std::cout << "图像正在处理中" << std::endl;
		}

		if (status == std::future_status::ready)
		{
			std::cout << "图像处理完毕,您要查看的图像是:" << fut.get() << std::endl;
		}

		std::cout << "----------------" << std::endl;
	}
	
}


int main()
{
	test02();
	return EXIT_SUCCESS;
}
#endif

赞(0)
未经允许不得转载:工具盒子 » C++ std::async 工具