async、packaged_task、promise、future的区别与使用
这篇文章从实践视角梳理了 std::async、std::packaged_task、std::promise 的定位差异,并给出它们“由底向上可封装”的关系。三者的角色边界三者都可与 std::future 联动,但抽象层级不同。async 更偏上层调度接口,支持异步/延迟执行策略。packaged_task 负责任…
使用方法 想要更详尽的介绍可以看看这本书,这几个函数牵扯到的内容是并发操作的同步,对应《C++并发编程实战》的第四章,这本书很难啃,有很多地方我也是断断续续看了几遍才有体会。 首先我们来看看让人迷惑的地方:std::aync、std::package_task、std::promise 这几个调用都能获得 std::future,那到底有什么区别呢?下面我们挨个来看看基本使用方法,再进行一个小总结。std::async 前言 async 这个词在其他语言中想必也不陌生,比如 js 里有await和async关键字用于执行异步任务等等,C++中的这个词表示一个函数,实际上也是用于异步执行。但是与js那个实现原理有很大的不同,简单的说就是js那个更加的上层,而C++这个偏底层。导致的区别就是js那两个关键字配合起来只为达到并发的效果,而其中的实现细节是非常复杂的,比如js实际上始终只用到了一个线程来实现了并发,这点类似于协程,具体到内部js是通过事件循环队列来实现的,所以你始终无法确切的理解到它的底层工作。 而C++的async与之相比,就好像一个原始人,需要你传递参数来确定它的工作机制,但和C++标准库的其他api相比,它却是非常高级的存在。 使用 在此之前先简单了解下C++的async使用方式,一个简单的代码如下:#include <future> #include <iostream> int find_the_answer_to_ltuae(); void do_other_stuff(); int main() { std::future<int> the_answer=std::async(find_the_answer_to_ltuae); do_other_stuff(); std::cout<<"The answer is "<<the_answer.get()<<std::endl; } 这个函数会返回一个future用于将异步的任务和主线程同步。也就是当你调用future的get方法时,它会等待异步任务完成,并得到对应的返回值。 关于 std::future 也有三个重要的api:wait、wait_for、get,前面两个不返回结果,只等待任务,wait_for可以设置等待的时间限制。 但是请注意,这个任务不一定是按照你想的那样异步执行的,它可能在你调用get方法的时候才执行,这个取决于你传递的第一个参数。std::launch::async:表示会开启一个线程去执行任务。std::launch::deferred:表示延迟调用,只有在外界需要得到结果的时候才调用。不传参数或者两者相与:表示由C++底层去调度,可能是async也可能是defferred。 实际上async函数在这几个C++的api里是最高级的,它同时拥有了异步与同步的能力。std::packaged_task 这个api与线程是没有任何关系的,它只是负责把普通的函数或者仿函数包装成方便异步转同步的任务。 比如我们开启一个线程去执行任务,我们又想对外界保有同步获取任务结果的能力,这个时候就需要用 std::package_task 来对现有的任务进行封装了。 如下代码: 以抖音用户的一次点赞行为对应的数据库底层需要调用的api举例子: plusVideoLike:增加对应视频的点赞数目,返回值为自定义的error类型 plusUserLikeList:增加用户喜欢的视频,返回值为自定义的error类型 很明显,这个两个过程互相并不影响,可以使用并发操作进行。UserService::addLike(int uid,int vid){ auto task1 = std::package_task<error(int)>{plusVideoLike}; auto task2 = std::package_task<error(int,int)>{plusUserLikeList}; auto f1 = task1.get_future(); auto f2 = task2.get_future(); std::thread t1([&](){ task1(vid); //video点赞+1 }); std::thread t2([&](){ task2(uid,vid); //用户点赞视频+1 }); //得到返回值的同时完成同步操作 if(f1.get() == 某错误){ } if(f2.get()== 某错误{ } } std::promise 从上面看下来,我们其实不难发现,async和packaged_task好像有某种联系?似乎async是封装了packaged_task的方便操作的api,没错大概就是这样。同样promise也是pa…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行