好得很程序员自学网
  • 首页
  • 后端语言
    • C#
    • PHP
    • Python
    • java
    • Golang
    • ASP.NET
  • 前端开发
    • Angular
    • react框架
    • LayUi开发
    • javascript
    • HTML与HTML5
    • CSS与CSS3
    • jQuery
    • Bootstrap
    • NodeJS
    • Vue与小程序技术
    • Photoshop
  • 数据库技术
    • MSSQL
    • MYSQL
    • Redis
    • MongoDB
    • Oracle
    • PostgreSQL
    • Sqlite
    • 数据库基础
    • 数据库排错
  • CMS系统
    • HDHCMS
    • WordPress
    • Dedecms
    • PhpCms
    • 帝国CMS
    • ThinkPHP
    • Discuz
    • ZBlog
    • ECSHOP
  • 高手进阶
    • Android技术
    • 正则表达式
    • 数据结构与算法
  • 系统运维
    • Windows
    • apache
    • 服务器排错
    • 网站安全
    • nginx
    • linux系统
    • MacOS
  • 学习教程
    • 前端脚本教程
    • HTML与CSS 教程
    • 脚本语言教程
    • 数据库教程
    • 应用系统教程
  • 新技术
  • 编程导航
    • 区块链
    • IT资讯
    • 设计灵感
    • 建站资源
    • 开发团队
    • 程序社区
    • 图标图库
    • 图形动效
    • IDE环境
    • 在线工具
    • 调试测试
    • Node开发
    • 游戏框架
    • CSS库
    • Jquery插件
    • Js插件
    • Web框架
    • 移动端框架
    • 模块管理
    • 开发社区
    • 在线课堂
    • 框架类库
    • 项目托管
    • 云服务

当前位置:首页>高手进阶
<tfoot draggable='sEl'></tfoot>

.NET(C#): Task.Unwrap扩展方法和async Lambda

.NET(C#): Task.Unwrap扩展方法和async Lambda

.NET(C#): Task.Unwrap扩展方法和async Lambda

目录

Task.Unwrap基本使用 Task.Factory.StartNew和Task.Run的Unwrap操作 使用案例:LINQ中的async Lambda

返回目录 Task.Unwrap基本使用

这个扩展方法定义在TaskExtensions类型中,命名空间在System.Threading.Tasks。Unwrap会把嵌套的Task<Task>或者Task<Task<T>>的结果提取出来。

就像这样,不用Unwrap的话:

static   void  Main( string [] args)

{

    doo();

     Task . Delay( - 1 ) . Wait();

}

static   async   void  doo()

{

     //运行嵌套的Task

     //Task返回Task<Task<string>>

     //第一个await后result类型为Task<string>

     var  result  =   await   Task . Run < Task < string >> (()  =>

        {

             var  task  =   Task . Run < string > (()  =>

                {

                     Task . Delay( 1000 ) . Wait();

                     return   "Mgen" ;

                });

             return  task;

        });

     //第二个await后才会返回string

     Console . WriteLine( await  result);

}

使用Unwrap后,结果可以直接从嵌套Task中提取出来:

static   async   void  doo()

{

     //运行嵌套的Task

     //Task返回Task<Task<string>>

     //await后类型为Task<string>,Unwrap后result类型为string

     var  result  =   await   Task . Run < Task < string >> (()  =>

        {

             var  task  =   Task . Run < string > (()  =>

                {

                     Task . Delay( 1000 ) . Wait();

                     return   "Mgen" ;

                });

             return  task;

        }) . Unwrap();

     //不需要await,result已经是string

     Console . WriteLine(result);

}

返回目录 Task.Factory.StartNew和Task.Run的Unwrap操作

简单地讲,Task.Factory.StartNew和Task.Run区别之一就有Task.Run会自动执行Unwrap操作,但是Task.Factory.StartNew不会,Task.Run就是Task.Factory.StartNew的更人性化封装,而Task.Factory.StartNew则是原始的执行。(另外关于更多的区别,推荐PFX Team的一篇非常给力的文章: Task.Run vs Task.Factory.StartNew )。

通过代码来验证:

var  task1  =   Task . Factory . StartNew( async  ()  =>   "Mgen" );

var  task2  =   Task . Run( async  ()  =>   "Mgen" );

Console . WriteLine(task1 . GetType());

Console . WriteLine(task2 . GetType());

输出:

System.Threading.Tasks.Task`1[System.Threading.Tasks.Task`1[System.String]]

System.Threading.Tasks.UnwrapPromise`1[System.String]

可以看到

使用Task.Factory.StartNew会返回原始的Task<Task<string>>。但是Task.Run则会直接返回async Lambda的结果,中间的Unwrap操作会自动进行。

返回目录 使用案例:LINQ中的async Lambda

文章讲述到这里,或许读者在想上述情况会不会很少见?不,任何使用async Lambda的情况都可能会出现上述情况,比如最近在搞一个WinRT的项目,使用LINQ去转换一些数据,但是许多WinRT的API只有异步执行的,这类问题就会出现,下方示例:

我们来进行一个再简单不过的LINQ Select操作,把一堆int转换成string,只不过转换过程是异步的,来看代码:

static   void  Main( string [] args)

{

    doo();

     Task . Delay( - 1 ) . Wait();

}

static   void  doo()

{

     //int数据

     var  ints  =   Enumerable . Range( 1 ,  10 );

     //转换并输出结果

     foreach  ( var  str  in  ints . Select( async  i  =>   await  Int2StringAsync(i)))

         Console . WriteLine(str);

}

//异步将int转换成string

static   async   Task < string >  Int2StringAsync( int  i)

{

     return   await   Task . Run < string > (()  =>  i . ToString());

}

上面代码正确吗?很多人会认为没问题的,Select方法通过一个async Lambda调用异步转换方法,并使用await异步等待结果, 那么async Lambda返回string ,str类型也是string,最后输出所以字符串。

但事实上程序运行后会输出一连串的“System.Threading.Tasks.Task`1[System.String]”,str变量根本不是string,而是Task<string>。上边的推断错在(上面黄字标注的)“async Lambda返回string”, async Lambda的结果并没有被await ,因此它会返回Task<string>,所以Select会返回一些列的Task<string>。

最简单的解决方案是,在处理结果的时候加上await,如下:

Console . WriteLine( await  str);

但是在多数情况下,我们使用LINQ会直接赋值给数据对象,这个数据对象的类型是固定的,这里需要一种更彻底的解决方案,直接在LINQ Select上解决掉。

那么还有一种解决方案就是不使用async Lambda,就不存在嵌套Task的问题,直接在Select中返回异步方法的Task的Result属性:

//int数据

var  ints  =   Enumerable . Range( 1 ,  10 );

//Select调用异步方法

IEnumerable < string >  strs  =  ints . Select(i  =>  Int2StringAsync(i) . Result);

如果一定要使用async Lambda,则必须将嵌套的Task进行Unwrap。(当然这里更多的是为了讨论技术本身,实际工作中没必要这么钻牛角尖呵呵。)

结合上面讲到的知识,使用Task.Factory.StartNew需要进行一个Unwrap,然后返回Task<T>的结果作为Select方法的最终返回值,代码:

//int数据

var  ints  =   Enumerable . Range( 1 ,  10 );

//Select调用异步方法

IEnumerable < string >  strs  =  ints . Select(i  =>

     Task . Factory . StartNew( async  ()  =>   await  Int2StringAsync(i)) . Unwrap() . Result);

而Task.Run的话,不需要Unwrap:

IEnumerable < string >  strs  =  ints . Select(i  =>

     Task . Run( async  ()  =>   await  Int2StringAsync(i)) . Result);

作者: Mgen

出处: www.cnblogs.com/mgen

本文版权归作者所有,欢迎以网址(链接)的方式转载,不欢迎复制文章内容的方式转载,其一是为了在搜索引擎中去掉重复文章内容,其二复制后的文章往往没有提供本博客的页面格式和链接,造成文章可读性很差。望有素质人自觉遵守上述建议。

如果一定要以复制文章内容的方式转载,必须在文章开头标明作者信息和原文章链接地址。否则保留追究法律责任的权利。

 

标签:  BCL ,  CSharp Language ,  Threading ,  TPL

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于.NET(C#): Task.Unwrap扩展方法和async Lambda的详细内容...

声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://www.haodehen.cn/did47996

更新时间:2022-09-24   阅读:62次

上一篇: 杭州ADC技术嘉年华两日总结SOA,去C

下一篇:wcf 随笔1

相关资讯

最新资料更新

  • 1.Java算法-求最大和的子数组序列
  • 2.算法学习笔记(16): 组合数学基础
  • 3.大牛,求一个最值,你能提出什么好的算法么
  • 4.国密SM4算法
  • 5.【LeetCode回溯算法#extra01】集合划分问题【火柴拼正方形、划分k个相等子集、公平发饼干
  • 6.联邦GNN综述与经典算法介绍
  • 7.python的简单四则运算语法树可视化
  • 8.C#插入排序算法
  • 9.【算法数据结构专题】[延时队列算法]史上手把手教你针对层级时间轮(TimingWheel)实现延时队
  • 10.详解Python AdaBoost算法的实现
  • 11.Java C++题解leetcode字符串轮转KMP算法详解
  • 12.基于准则匹配的图像对准
  • 13.vivo 故障定位平台的探索与实践
  • 14.特定领域知识图谱(Domain-specific KnowledgeGraph:DKG)融合方案:技
  • 15.剑指 Offer 32 - I. 从上到下打印二叉树(java解题)
  • 16.初探富文本之CRDT协同算法
  • 17.C语言中深度优先搜索(DFS)算法的示例详解
  • 18.深度解读Python如何实现dbscan算法
  • 19.算法总结--ST表
  • 20.RAM算法原理

CopyRight:2016-2025好得很程序员自学网 备案ICP:湘ICP备09009000号-16 http://www.haodehen.cn
本站资讯不构成任何建议,仅限于个人分享,参考须谨慎!
本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
本网站刊载的所有内容(包括但不仅限文字、图片、LOGO、音频、视频、软件、程序等)版权归原作者所有。任何单位或个人认为本网站中的内容可能涉嫌侵犯其知识产权或存在不实内容时,请及时通知本站,予以删除。

网站内容来源于网络分享,如有侵权发邮箱到:kenbest@126.com,收到邮件我们会即时下线处理。
网站框架支持:HDHCMS   51LA统计 百度统计
Copyright © 2018-2025 「好得很程序员自学网」
[ SiteMap ]