HTML5技术

C#与C++的发展历程第三 - C#5.0异步编程巅峰 - hystar(16)

字号+ 作者:H5之家 来源:博客园 2016-01-15 10:03 我要评论( )

先来看一下和.NET Task基本等价的task类型。这也是微软C++扩展中并发异步线程管理的核心类型之一。微软围绕concurrency::task的设计的一些方法与C#中的Task相关方法真的非常下。下面的表格对比了C#的Task与C++中的c

先来看一下和.NET Task基本等价的task类型。这也是微软C++扩展中并发异步线程管理的核心类型之一。微软围绕concurrency::task的设计的一些方法与C#中的Task相关方法真的非常下。下面的表格对比了C#的Task与C++中的concurrency::task。有C# Task基础的话,对于concurrency::task很容易就能上手。

 

  C# Task C++ concurrency::task

构造 方式1 constructor constructor

构造 方式2 Task.Factory.StartNew()

用于异步 - create_task()

构造 方式3

用于并行 - make_task()

返回task_handle,和task_group等同用。

阻塞 - 等待完成 task.Wait() task::wait()

阻塞 - 等待获取结果 GetAwaiter().GetResult() task::get()

任务状态类型 TaskStatus concurrency::task_status

并行 - 等待全部 Task.WhenAll() concurrency::when_all

并行 - 等待部分 Task.WhenAny() concurrency::when_any

异步 - 任务延续 Task.ContinueWith() task::then()

 

接着讨论一下本节的重点内容,微软给C++带来的异步支持。

普通异步

看过之前介绍C#异步的部分,可以知道支持异步的系统无非就由以下以下几部分组成:任务创建、任务延续、任务等待、取消、进度报告等。依次来看一下ppltask.h中支持这些部分的方法。

create_task方法可以将函数对象(广义上的函数对象包含如lambda表达式,在C++11中也多用lambda表达式作为函数对象)包装成task类对象。如上文所述,定义在ppltask.h中,位于concurrency命名空间下的task类和异步方法关系最密切。下面的代码示例了concurrency::task的创建。

task<int> op1 = create_task([]()   {        return 0;   });

在C++11中一般都使用auto直接表示一些复杂的类型,让编译器去推断。例子中写出完整的类型可以让读者更好的理解方法的返回类型。

而类似于.NET Task中的ContinueWith方法的task::then方法,基本使用如下:

op1.then([](int v){        return 0;   });

在C++中由于没有类似C#中async/await关键字的支持,所以后续任务不能像C#中那样直接跟在await ...语句后,必须通过task::then方法来设置。

then方法也可以实现链式调用,如:

auto t = create_task([]()   {        //do something   }).then([](int v){        return 0;   });

关于后续代码执行上下文的问题,如果create_task方法接受的函数对象返回的是task<T>或task<void>则后续代码会在相同的线程上下文运行,如果返回的是T或void则后续任务会在任意上下文运行。可以使用concurrency::task_continuation_context来更改这个设置。具体用法是将task_continuation_context传给task::then其中那些接受task_continuation_context类型参数的重载。如果参数值为concurrency::task_continuation_context::use_arbitrary,则表示指定延续在后台线程上运行,如果参数值为concurrency::task_continuation_context::use_current,则表示指定延续在调用了task::then的线程上运行。如:

 

auto t = create_task([]()   {        //do something   }).then([](int v){        //do something else;   },task_continuation_context::use_arbitrary());//then()中传入的代码将在后台线程执行,相对于C#中配置ConfigAwait(false)。

对于取消和异步的支持,将在下一小段进行介绍,那里的实现方式同样可以应用到这一部分中。

使用create_task的方式创建task的方法只用于C++内部对task的管理。如果是希望将异步作为WinRT组件发布需要使用下面介绍的create_async。

如果是纯C++中处理多线程任务,除了使用Windows中所提供的task,还可以考虑C++11标准库中的thread,后者跨平台更好。后文会有一部分介绍C++11的thread。如果是对C#的TPL模型很熟悉,转到C++使用ppltask.h中的task会发现模型一致性很高。

 

支持WinRT的异步

1. 提供WinRT标准的异步方法

通过create_async方法可以将函数转为异步函数,即这个方法是返回IAsyncInfo对象的。通过这个方法可以将代码包装成WinRT中标准的异步方法供其它语言调用。被包装的代码一般是可调用对象,在C++11中一般都使用Lambda表达式。返回的IAsyncInfo的具体类型(上文介绍的四种之一)是有传入的参数决定的。

create_async的声明:

template<typename _Function> __declspec(    noinline ) auto create_async(const _Function& _Func) -> decltype(ref new details::_AsyncTaskGeneratorThunk<_Function>(_Func));

可以看到为了确定这个模板方法的返回类型使用了C++11的decltype和位置返回类型等新特性。

通常情况下,传入create_async的函数对象的方法体是一般的代码。还以把create_task方法的调用传入create_async接收的lambda表达式的方法体中,create_task返回的concurrency::task也可以配置一系列的then(),最终这些配置都将反应给最外部的create_async的包装。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 2年前端学习历程,与找不到工作的悲愤与吐槽!(100%真实经历,看博主怎么一步步走向失业) - 蒋启钲

    2年前端学习历程,与找不到工作的悲愤与吐槽!(100%真实经历,看博

    2017-03-29 11:00

  • 开源第三方登录组件OAuthLogin2.0 支持QQ,阿里巴巴,淘宝,京东,蘑菇街,有赞等平台 - 大壮他哥

    开源第三方登录组件OAuthLogin2.0 支持QQ,阿里巴巴,淘宝,京东,蘑菇街

    2017-01-20 15:00

  • 从零到百亿互联网金融架构发展史 - 纯洁的微笑

    从零到百亿互联网金融架构发展史 - 纯洁的微笑

    2017-01-14 13:00

  • 记一次企业级爬虫系统升级改造(四):爬取微信公众号文章(通过搜狗与新榜等第三方平台) - 彩色铅笔

    记一次企业级爬虫系统升级改造(四):爬取微信公众号文章(通过搜狗

    2017-01-12 10:01

网友点评