异步编制程序类别第03章 本人写异步代码

写在前头

  在学异步,有位园友推荐了《async in
C#5.0》,没找到中文版,恰巧也想升高下英文,用自家工巧的英文翻译一些注重的部分,纯属娱乐,简单分享,保持学习,谨记谦虚。

  借使你以为那件事情没意义翻译的又差,尽情的踩吧。借使您认为值得鼓励,感激留下你的赞,愿爱技术的园友们在随后每2次应该能够突破的时候,不采纳知难而退。在每二次应该单独思想的时候,不采用与世浮沉,应该大力的时候,不选择尽量,不辜负每一秒存在的意义。

  
转发和爬虫请表明原作链接http://www.cnblogs.com/tdws/p/5628538.html,博客园
蜗牛 2016年6月27日。

目录

第01章 异步编制程序介绍

第02章 为啥使用异步编制程序

第03章 手动编写异步代码

    .NET中的一些异步情势
    最不难易行的异步形式
    关于Task的介绍
    手动编写异步代码的难点
    运用手写异步代码转换示例(第①章结尾2个演示)

第04章 编写Async方法

第05章 Await终究做了怎么

第06章
以Task为根基的异步格局

第07章 异步代码的一部分工具

第08章 哪个线程在运作你的代码

第09章 异步编制程序中的极度

第⑩章 并行使用异步编制程序

第①1章 单元测试你的异步代码

第①2章 ASP.NET应用中的异步编制程序

第一3章 Win本田CR-VT应用中的异步编制程序

第②4章 编写翻译器在底层为您的异步做了如何

第叁5章 异步代码的习性

手动编写异步代码

  在本章,大家将会商讨一些关于不使用C#5.0主要字async的异步编制程序。那种方法纵然已经是过去的技术,恐怕你不会再利用,但那对于你通晓异步编程表象背后产生了哪些工作是很首要的。也因为那一点,小编将会急迅的叙说示例,仅仅重视揭破出对你知道有救助的地点。

 

.NET中的一些异步方式

  正如小编事先涉嫌的,Silverlight只提供了像web访问的异步版本API。那里有一个事例,你能够下载一个网页,并展现它:

private void DumpWebPage(Uri uri)
{
WebClient webClient = new WebClient();
webClient.DownloadStringCompleted += OnDownloadStringCompleted;
webClient.DownloadStringAsync(uri);
}
private void OnDownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs eventArgs)
{
m_TextBlock.Text = eventArgs.Result;
}

  那种API是根据事件的异步格局(EAP)。那个想法是想替代单线程方法去下载网页,即阻塞型代码会平素等到下载结束再调用一个办法或接触2个事变。那个措施看起来和一块代码一样,除了无再次回到类型。那一个事件也有四个专门的eventArgs类型,它涵盖值检索。

  大家在调用那些方法前注册了事件。该办法立刻回去,当然那是因为它是异步代码。然后在明日的有个别时刻触发。这种格局鲜明很复杂,不仅仅是因为你要将它分成像例子一样的多个办法。最根本的是,你注册了三个日子增多了复杂。若是说笔者还要用平等的WebClient实例处理其余需求,那么你大概不期望以此时刻依然被增大着还要再一次实施三回。

  在.NET功效中另贰个异步方式设计IAsyncResult接口。在那之中三个例证正是DNS查找主机名的IP地址,BeginGetHoseAddress。那种规划要求多少个艺术,叁个是发端履行的BeginMethodName,另3个是履行结束EndMethodName,即你的回调方法。

private void LookupHostName()
{
object unrelatedObject = "hello";
Dns.BeginGetHostAddresses("oreilly.com", OnHostNameResolved, unrelatedObject);
}
private void OnHostNameResolved(IAsyncResult ar)
{
object unrelatedObject = ar.AsyncState;
IPAddress[] addresses = Dns.EndGetHostAddresses(ar);
// Do something with addresses
...
}

  至少那种艺术不会际遇残留注册事件的影响,可是那也极度的对API扩展了复杂。有七个方式而不是二个,小编以为很不自然。

  那二种异步情势都亟需您分为五个艺术来书写。IAsyncResult情势要你从第②个格局中向第①个方法传递有些参数,就像是自个儿传递了string类型的”hello”。不过那种艺术很复杂,固然你不须要那些参数,依旧不得不传递它,并且迫使你转移为object类型。

 

最不难易行的异步形式

  能够说上边那段代码拥有异步行为,尽管不选拔async关键字,也不用向方法传递委托:

void GetHostAddress(string hostName, Action<IPAddress> callback)

  小编发觉那种办法比其他措施进一步易用。

private void LookupHostName()
{
GetHostAddress("oreilly.com", OnHostNameResolved);
}
private void OnHostNameResolved(IPAddress address)
{
// Do something with address
...
}

  差别于三个法子的情势,像作者原先提到的,使用异步方法或然用lambda表明式做回调。它装有首要的好处便是能够在第四个章程中做客变量。

private void LookupHostName()
{
int aUsefulVariable = 3;
GetHostAddress("oreilly.com", address =>
{
// Do something with address and aUsefulVariable
...
});
}

  这几个Lambda有有个别不便阅读,并且普通假如您利用多重的异步编制程序,你将急需多多Lambda表明式互相嵌套,你的代码将会急迅变得纵横交叉和麻烦处理。

  那种简单方法的弱点在于他们不再对调用者抛出万分。在从前.NET异步编制程序中,调用EndMethodName恐怕取得Result属性时,将会再一次抛出越发,所以在代码中大家得以对应的处理万分。相反,他们或许在有些错误地点停下也许根本不去处理。

 

关于Task的介绍

  职责并行实在.NET
Framework4.0本子中出产的。其最主要的地方是Task类,即表示2个正值实践的操作。
泛型版本的Task<T>, 当操作完结时重临类型为T的值。

   在C#5.0
async功用上大家多量的应用了Task,大家将会稍后钻探。可是就是没有async,你如故得以选用Task,越发是运用Task<T>来异步编制程序。那样做就行,你从头3个赶回Task<T>的操作,然后使用ContinueWith方法注册你的回掉方法。

private void LookupHostName()
{
Task<IPAddress[]> ipAddressesPromise = Dns.GetHostAddressesAsync("oreilly.com");
ipAddressesPromise.ContinueWith(_ =>
{
IPAddress[] ipAddresses = ipAddressesPromise.Result;
// Do something with address
...
});
}

  Task的长处就如这么些DNS只要求叁个主意,使API尤其整洁。全体调用异步行为有关的逻辑都可在Task类个中,所以它不要求在每二个格局里都开始展览复制。那一个逻辑能够做过多至关心尊敬要的事务,比如拍卖分外和一起上下文(SynchronizationContexts)。这个,大家将会在第玖章探究,对于在2个一定线程上推行callback很有用处(比如UI线程)。

  最重点的是,Task给咱们提供一种接纳异步的周旋抽象的操作方法。大家能够动用那种组合型去编写大家的工具,即在诸多亟需采取Task的景色下提供给一些立竿见影的表现。大家将会面到众多连锁的工具组件(utilities)在第八章个中。

 

手动编写异步代码的题材

  
正如我们来看的,大家有诸多主意来贯彻异步编制程序。有一对措施比此外艺术整洁易懂易用,不过也期待你早已看到他们共有的败笔。你打算写的次序不得不分为三个措施:实际的方法和回调方法。还有使用异步方法或嵌套多次lambda表达式作为回调,使你的代码一环套一环难以知晓。

  实际上那里还有另一个标题。大家早就说过调用2次异步方法的景色,但是当你需求三个异步时会产生什么呢?更倒霉的是,倘诺弄须要在循环中调用异步又会爆发什么样啊?你为贰个艺术是利用递归方法,那又比日常的轮回难以阅读多了。

private void LookupHostNames(string[] hostNames)
{
LookUpHostNamesHelper(hostNames, 0);
}

private static void LookUpHostNamesHelper(string[] hostNames, int i)
{
Task<IPAddress[]> ipAddressesPromise = Dns.GetHostAddressesAsync(hostNames[i]);
ipAddressesPromise.ContinueWith(_ =>
{
IPAddress[] ipAddresses = ipAddressesPromise.Result;
// Do something with address
...
if (i + 1 < hostNames.Length)
{
LookUpHostNamesHelper(hostNames, i + 1);
}
});
}

  哇!

  在那一个异步编制程序方式中,引发的另1个标题就是亟需费用大批量代码。假如你写一些异步代码,期望在其它省方接纳,你只可以提供API,假如API混乱只怕忘记当时的初衷无法领略的话,将会一举两得。异步代码是会“传染”的,因而不但你须求异步API,还影响调用者和调用者的调用者,知道一切程序乱成一团。

 

运用手写异步代码转换示例(第③章结尾2个示范)

  再来谈谈第二章末尾三个演示,大家谈论了3个会因从网站下载icons,造成UI线程阻塞,并导致出现应用程序未响应的WPF
UI app。未来我们将会看出,将它转载成手写的异步代码。

  第首先要做的正是找到一个异步API的版本,小编用(WebClient。下载文件)。正如作者辈曾经看到的,WebClient方法应用基于事件的异步格局(EAP),所以大家得以在始发下载在此之前注册八个事件作为回调方法。

private void AddAFavicon(string domain)
{
WebClient webClient = new WebClient();
webClient.DownloadDataCompleted += OnWebClientOnDownloadDataCompleted;
webClient.DownloadDataAsync(new Uri("http://" + domain + "/favicon.ico"));
}
private void OnWebClientOnDownloadDataCompleted(object sender,
DownloadDataCompletedEventArgs args)
{
Image imageControl = MakeImageControl(args.Result);
m_WrapPanel.Children.Add(imageControl);
}

  当然,大家的确实属于一起的逻辑要被分为五个措施。作者不希罕使用Lambda来代替刚才的EAP,因为lambda会冒出在真的初步下载前,小编觉得那是不可读的。

  那个本子的言传身教也得以在线(https://bitbucket.org/alexdavies74/faviconbrowser)找到,(//译者注释:不运行此程序也没关系,主要是体会下思路就好)在manual分支。如果你运行它,不进界面可相应,图标也会逐一出现。正因此,我们也引入了一个bug,现在由于所有下载操作同时开始,icons的排序由其下载先后决定,而不是由我的先后请求来决定。如果你想检验自己是否理解手动编写异步代码,我建议你尝试着解决此bug。在orderedManual分支下(上面列出的站点下)提供了一个解决方案。其他更有效的解决方案也是有可能的。

写在背后

27号入职,花了三日的业余时间,坎坎坷坷的翻译了第3章。如若你对你有些许益处,不要吝啬你的赞,给个鼓励。不标准和内需补给的地方,也请前辈们不吝赐教,笔者将谦虚改进。下一章将会介绍 “编写Async方法