当前位置:首页 » 编程软件 » net异步编程

net异步编程

发布时间: 2024-02-28 04:28:26

㈠ 如何正确理解.NET 4.5和C#5.0中的async/await异步编程模式

这个await,其实只是把对老版本C#迭代器的惯用法官方化了。现在很多平台都因为一些原因不得不用旧版本的C#,比如unity,想异步那只能通过迭代器来做。

async、迭代器都是语法糖,编译器会帮你实现成一个状态机匿名类,实例里面hold住一些临时变量,记录一下当前状态。根据你写的yield/await,把一个异步方法拆成几个同步block,根据一定规则定期的去MoveNext一下,Current是Task那我就根据你配置的线程上下文决定把这个Task跑在哪个线程上。

那么用await修饰的异步方法是在哪个线程中被调用的?为什么上面这个事件处理方法不会阻塞GUI?
我还看到其它一些描述是说使用async/await异步模式不会生成新的线程,那么只在原来已有线程的基础上面如何做到异步运行?
题主这个例子这个方法就是在UI线程调用的,并且没有ConfigureAwait(false),所以会在当前await时捕捉的UI线程上下文执行之后的同步block。
至于为什么不会阻塞,可以简单理解为执行了第一个block,碰到Delay(4000),给UI线程的定时器挂一个4000时间之后再调用下一个同步块的回调。

看题主说的书名像是国产的书,这方面还是看《CLR via C#》或者《Concurrency in C# cookbook》比较好。

㈡ 什么是异步编程

传统的同步编程是一种请求响应模型,调用一个方法,等待其响应返回.

异步编程就是要重新考虑是否需要响应的问题,也就是缩小需要响应的地方。因为越快获得响应,就是越同步化,顺序化,事务化,性能差化。

异步编程通常是通过fire and forget方式实现,发射事件后即忘记,做别的事情了,无需立即等待刚才发射的响应结果了。(发射事件的地方称为生产者,而将在另外一个地方响应事件的处理者称为消费者).异步编程是一种事件驱动编程,需要完全改变思路,将“请求响应”的思路转变到“事件驱动”思路上,是一种软件编程思维的转变.下面几种你看参考一下

1、异步编程模型 (APM) 模式(也称为 IAsyncResult 模式),其中异步操作要求 Begin 和 End 方法(例如,异步写操作的 BeginWrite 和 EndWrite)。对于新的开发工作不再建议采用此模式。

2、基于事件的异步模式 (EAP) 需要一个具有 Async 后缀的方法,还需要一个或多个事件、事件处理程序、委托类型和 EventArg 派生的类型。EAP 是在 .NET Framework 2.0 版中引入的。对于新的开发工作不再建议采用此模式。
3、基于任务的异步模式 (TAP),该模式使用一个方法表示异步操作的启动和完成。.NET Framework 4 中引入了 TAP,并且是 .NET Framework 中异步编程的建议方法。

㈢ C#几种异步编程

1、异步编程模型 (APM) 模式(也称为 IAsyncResult 模式),其中异步操作要求 Begin 和 End 方法(例如,异步写操作的 BeginWrite 和 EndWrite)。对于新的开发工作不再建议采用此模式。

2、基于事件的异步模式 (EAP) 需要一个具有 Async 后缀的方法,还需要一个或多个事件、事件处理程序、委托类型和 EventArg 派生的类型。EAP 是在 .NET Framework 2.0 版中引入的。对于新的开发工作不再建议采用此模式。
3、基于任务的异步模式 (TAP),该模式使用一个方法表示异步操作的启动和完成。.NET Framework 4 中引入了 TAP,并且是 .NET Framework 中异步编程的建议方

㈣ 如何正确理解.NET 4.5和C#5.0中的async/await异步编程模式

相对于之前Begin/End模式和事件模式,async/await模式让程序员得以用同步的代码结构进行异步编程。async/await入门很方便,但是深入理解却涉及很多领域,如线程池、同步上下文等等。我断断续续接触了几个月,稍微有一些心得:


await的作用是等待异步Task完成,并不是阻塞的。举个例子,一个异步方法:

publicasyncTaskCaller()
{
Action0();
awaitMethod();
Action3();
}

publicasyncTaskMethod()
{
Action1();
awaitTask.Delay(1000);
Action2();
}

A.当你在非UI线程A上执行Caller(),将完成以下几件事:

  1. [线程A]执行Action0()

  2. [线程A]调用await Method()

  3. [线程A]执行Action1()

  4. [线程A]启动任务Task.Delay(1000),并在线程池里安插一个新任务,在Task.Delay(1000)完成后,由另一个线程执行6

  5. [线程A]去处理别的事情

  6. [线程B]执行Action2()

  7. [线程B]await Method()返回

  8. [线程B]执行Action3()

其中,线程A和线程B并不保证是同一个线程。如果你在await前后打印线程ID,你会发现ID是不同的。


B.当你在UI线程上执行Caller(),过程有了变化:

  1. [UI线程]执行Action0()

  2. [UI线程]调用await Method()

  3. [UI线程]执行Action1()

  4. [UI线程]启动任务Task.Delay(1000),并在线程池里安插一个新任务,在Task.Delay(1000)完成后,由另一个线程执行6

  5. [UI线程]去处理别的事情

  6. [线程C]在UI线程的同步上下文中执行7(类似于在窗体类上执行Invoke()方法)

  7. [UI线程]执行Action2()

  8. [UI线程]await Method()返回

  9. [UI线程]执行Action3()

可见,当使用await方法的线程为UI线程时,程序默认会通过第6步,保证await前后是同一个线程ID。这个当然是有一定性能牺牲的(甚至会造成死锁,在D里会讨论),如果你不想在await完成后回到UI线程,见C。


C. 你可以在UI线程上使用await XXX().ConfigureAwait(false)去替代awaitXXX(),来禁止当await XXX()结束时恢复线程。举个例子,执行下列代码是没问题的(如B里描述的):

privateasyncvoidbutton1_Click(objectsender,EventArgse)
{
this.Text="123";
awaitTask.Delay(1000);
this.Text="321";
}

但是,执行下列代码就会发生“线程间操作无效”的错误:

privateasyncvoidbutton1_Click(objectsender,EventArgse)
{
this.Text="123";
awaitTask.Delay(1000).ConfitureAwait(false);
this.Text="321";//线程间操作无效
}

因为执行

this.Text="321";

的线程已经不再是UI线程。


D. 顺便一提,Task.Wait()方法,相比于await Task,会同步地执行Task。但是,如果你在UI线程上Wait的Task里本身又有await,那么将会产生死锁:

privatevoidFoo(objectsender,EventArgse)
{
this.Text="123";
Method().Wait();//此处发生死锁
this.Text="321";//这行永远也不会执行
}
privateasyncTaskMethod()
{
awaitTask.Delay(1000);
}

为什么呢?Method().Wait()会阻塞UI线程等待Method()完成,但是参照B过程,在await完成后,Method()完成前,是需要恢复到UI线程的,但是此时UI线程已经被阻塞了,因此死锁就发生了。

要避免这个死锁,可以参照C。


E. 说出来你可能不信,上面的都是我手打的。在内容上虽然不一定严谨,但希望对楼主和其它新接触TAP的朋友有一定启发。

热点内容
w7恢复出厂设置密码是多少 发布:2024-11-16 05:23:49 浏览:790
方周编译器 发布:2024-11-16 05:23:12 浏览:659
数据库监控工具 发布:2024-11-16 05:23:07 浏览:957
存储器题型 发布:2024-11-16 05:23:06 浏览:85
怎么设置电脑配置信息 发布:2024-11-16 05:04:26 浏览:980
推荐系统php 发布:2024-11-16 05:03:42 浏览:11
加密mp3文件 发布:2024-11-16 04:43:04 浏览:842
观澜ug编程培训 发布:2024-11-16 04:42:15 浏览:639
注册表中心服务器地址生成规则 发布:2024-11-16 04:30:19 浏览:962
安卓360双系统怎么设置 发布:2024-11-16 04:29:32 浏览:756