c++介绍异步任务 七

在同步模式下,执行完一个任务后才可以执行下一个任务。而异步任务是将函数调用交给另外一个线程执行,在异步任务执行的同时,原有线程可以继续执行后续的代码,在需要的时候再去获得函数执行的结果。

在c++标准库中有异步函数调用和同步函数调用

 async函数(函数执行策略,调用函数,调用函数参数)

 下面代码 是用异步任务计算累计的程序

#include<array>
#include<vector>
#include<thread>
#include<iostream>
#include<mutex>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<semaphore>
#include<syncstream>
#include<numeric>
#include<future>
using namespace std;
float Computer(vector<float>& v)
{
	this_thread::sleep_for(chrono::seconds(2));
	auto r = accumulate(v.begin(), v.end(), 0.0f);
	osyncstream(cout) << "执行任务线程id:" << this_thread::get_id() << endl;
	return r;
}
int main()
{
	const int RN_MAX = 1000000;
	vector<float>numbers(100,0.0f);

	generate(numbers.begin(), numbers.end(), [&] {
		return 1.0;
	});
	chrono::steady_clock::time_point begin = chrono::steady_clock::now();
	cout << "创建任务线程Id: " << this_thread::get_id() << endl;
	future<float>result;
	result = async(launch::async,Computer,ref(numbers));

	this_thread::sleep_for(chrono::seconds(2));
	auto r = result.get();
	cout << "result= " << r << endl;
	chrono::steady_clock::time_point end = chrono::steady_clock::now();
	cout << "任务耗时= " << chrono::duration_cast<chrono::milliseconds>(end - begin).count() << "ms" << endl;

}

输出结果

主函数和Computer函数都设置了两秒的延时,而整个程序执行过程用了两秒,可见主函数和异步函数是并行执行的,除此之外两个线程的id号也不相同。

异步函数调用策略有三种

1.异步策略时相当于新建一个线程或者使用线程池中的一个线程,在线程中 调用一个函数。

2.推迟策略,当future返回一个对象时,只要用于存储函数指针或者对象以及实参的拷贝,当调用get时会调用它存储的这个函数。

3.延迟策略或者异步策略

看下三种策略例子

#include<array>
#include<vector>
#include<thread>
#include<iostream>
#include<mutex>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<semaphore>
#include<syncstream>
#include<numeric>
#include<future>
#include<map>
using namespace std;
float Computer(vector<float>& v)
{
	this_thread::sleep_for(chrono::seconds(2));
	auto r = accumulate(v.begin(), v.end(), 0.0f);
	osyncstream(cout) << "执行任务线程id:" << this_thread::get_id() << endl;
	return r;
}
int main()
{
	const int RN_MAX = 1000000;
	vector<float>numbers(100, 0.0f);

	generate(numbers.begin(), numbers.end(), [&] {
		return 1.0;
	});

	map<string, launch>m =
	{
		{"默认",(launch)0},
		{"异步",launch::async},
		{"推迟",launch::deferred},
	};

	for (auto& p : m)
	{
		cout << "\n*************************\n策略:" << p.first << endl;
		chrono::steady_clock::time_point begin = chrono::steady_clock::now();
		cout << "创建任务线程Id: " << this_thread::get_id() << endl;
		future<float>result;
		if (int(p.second) != 0)
		{
			if(int(p.second) == 1)
				result = async(launch::async, Computer, ref(numbers));
			else
			{
				result = async(launch::deferred, Computer, ref(numbers));
			}
		}
		else
		{
			result = async(Computer,ref(numbers));
		}
		this_thread::sleep_for(chrono::seconds(2));

		if (result.wait_for(chrono::milliseconds(0)) == future_status::deferred)
		{
			cout << "任务推迟" << endl;
		}
		auto r = result.get();
		cout << "result= " << r << endl;
		chrono::steady_clock::time_point end = chrono::steady_clock::now();
		cout << "任务耗时= " << chrono::duration_cast<chrono::milliseconds>(end - begin).count() << "ms" << endl;
	}
}

打印结果

可见推迟策略执行任务是在主线程中。

接下来看下打包任务

调用packaged_task对象,我们可以使用成员函数future获得对象,返回的结果会存储future中的共享状态中。

#include<array>
#include<vector>
#include<thread>
#include<iostream>
#include<mutex>
#include<algorithm>
#include<sstream>
#include<iomanip>
#include<semaphore>
#include<syncstream>
#include<numeric>
#include<future>
#include<map>
using namespace std;
float Computer(vector<float>& v)
{
	this_thread::sleep_for(chrono::seconds(2));
	auto r = accumulate(v.begin(), v.end(), 0.0f);
	osyncstream(cout) << "执行任务线程id:" << this_thread::get_id() << endl;
	return r;
}
int main()
{
	const int RN_MAX = 1000000;
	vector<float>numbers(100, 0.0f);

	generate(numbers.begin(), numbers.end(), [&] {
		return 1.0;
	});

	
	cout << "创建任务线程Id: " << this_thread::get_id() << endl;
	packaged_task<float(vector<float>&)>task(Computer);
	cout << "***********************直接调用********************" << endl;
	future<float>result = task.get_future();
	task(numbers);
	cout << "reuslt=" << result.get() << endl;
	task.reset();//重置内部的future对象
	cout << "************************使用线程调用***************" << endl;
	result = task.get_future();
	thread t(move(task),ref(numbers));
	cout << "result = " << result.get() << endl;
	t.join();
}

通常我们 使用第二种方式将一个打包的任务扔到一个线程中去,这样才能实现真正的优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值