网上很多异步编程的文章,提供一篇入门:

异步编程模型

.net支持3种异步编程模式:

 msdn:https://docs.microsoft.com/zh-cn/dotnet/standard/asynchronous-programming-patterns/

推荐大家先看我写的,再针对各个部分查看msdn的详细内容

1、  异步编程模型 (APM:Asynchronous Programming Model)

使用 IAsyncResult 设计模式的异步操作是通过名为 BeginOperationName 和 EndOperationName 的两个方法来实现的,这两个方法分别开始和结束异步操作 OperationName

开始异步操作

BeginOperationName 方法开始异步操作 OperationName,并返回实现 IAsyncResult 接口的对象。 IAsyncResult 对象存储有关异步操作的信息。

结束异步操作

EndOperationName 方法用于结束异步操作 OperationName。 EndOperationName 方法的返回值与其同步对应方法的返回值类型相同,并且是特定于异步操作的。

 

在msdn上是以文件读取作为例子。这里以更简单的例子进行演示。如果可以进行单元测试的,可直接在单元测试中进行,没有的则可以使用控制台应用程序进行。

委托对象有以BeginInvoke和EndInvoke,所以使用委托进行演示:

 

1.1要被调用的方法:这是一个带有参数且有字符串返回值的方法

 1 static string ShowInfo(string info)
 2 
 3  {
 4 
 5      Console.WriteLine("方法调用"+info);
 6 
 7      int result = 0;
 8 
 9      for (int i = 1; i < 100; i++)
10 
11      {
12 
13          result += i;
14 
15          System.Threading.Thread.Sleep(10);
16 
17      }
18 
19      return result.ToString();
20 
21  }

 

以上方法,一个输入,一个输出,都是字串,方法体中会打印方法调用字样,并打印输入字串。然后计算1到99的数字的和值,其中每次数字输出会休眠10毫秒。最后返回和值。

以上仅为演示和模拟算法效果。

 

1.2

 

 1 //委托对象
 2 
 3 static SayHi xx = new SayHi(ShowInfo);
 4 
 5 static void Main(string[] args)
 6 
 7 {
 8 
 9     //回调委托对象
10 
11     AsyncCallback callback = new AsyncCallback(show);
12 
13     //异步开始
14 
15     var ret=xx.BeginInvoke("", null, null);
16 
17     string result = xx.EndInvoke(ret);
18 
19     Console.WriteLine(result);
20 
21      Console.Read();
22 
23 }

 

 

以上方法,先定义了一个与1.1中方法ShowInfo方法匹配的委托:即此委托对象可以apm异步调用,即异步调用 ShowInfo方法。

在BeginInvoke时,第二个参数,即回调方法设置为null,即不使用回调方法。

BeginInvoke方法如下:

public IAsyncResult BeginInvoke (

    InvokeArgs invokeArgs,

    AsyncCallback callback,

    Object userState

)

第一个参数是委托方法的参数:ShowInfo方法的输入参数

第二个参数是回调方法:完成调用ShowInfo方法后要执行的动作,这里是个(回调)方法

第三个参数是操作关联的可选状态

 

EndInvoke方法如下:

public InvokeCompletedResult EndInvoke (

    IAsyncResult asyncResult

)

参数是 BeginInvoke方法的返回值。而返回值是InvokeCompletedResult类型,委托对象的返回值,即方法ShowInfo的返回值。

 

BeginInvoke方法的返回值为IAsyncResult类型。第二个参数为AsyncCallback类型。

AsyncCallback是一个委托类型,查看它的定义是这样的:

public delegate void AsyncCallback(IAsyncResult ar);

它是一个无返回值参数是IAsyncResult类型的委托。所以回调方法签名与与这相符,定义回调方法如下:

//回调方法

 static void show(IAsyncResult asr)

 {

     string result = xx.EndInvoke(asr);

     Console.WriteLine(result);

     Console.WriteLine("结束");

 }

  

2、  基于事件的异步模式 (EAP)

 

 未完待

 

3、  基于任务的异步模式 (TAP)

与之离不开的是Task类。它的构造方法如下:

 

 即,接收action委托。

最简单的调用如下:

 1 static void Main(string[] args)
 2 
 3   {
 4 
 5       Action act=delegate()
 6 
 7       {
 8 
 9           Console.WriteLine("方法打印信息");
10 
11       };
12 
13       Task t = new Task(act);
14 
15       t.Start();
16 
17       Console.Read();
18 
19   }

 

通过匿名方法,lambda可以省略为:

 1 static void Main(string[] args)
 2 
 3  {
 4 
 5      //Action act=delegate()
 6 
 7      //{
 8 
 9      //    Console.WriteLine("方法打印信息");
10 
11      //};
12 
13      Task t = new Task(()=>{
14 
15          Console.WriteLine("方法打印信息");
16 
17      });
18 
19      t.Start();
20 
21      Console.Read();
22 
23  }

 

此外,可以通过Task的静态工厂创建任务,如下:

 

 1 Task t = Task.Factory.StartNew(
 2 
 3                 () => {
 4 
 5                     Console.WriteLine("方法打印信息");
 6 
 7                 }
 8 
 9                 );
10 
11             t.Start();
12 
13             Console.Read();

 

总之,效果是一样的。

以下代码用于演示同步:

 1 static void Main(string[] args)
 2 
 3   {
 4 
 5       Console.WriteLine(1);
 6 
 7       Console.WriteLine(2);
 8 
 9       Task taskA = Task.Run(() => { Thread.Sleep(2000); Console.WriteLine(3); });
10 
11       try
12 
13       {
14 
15           taskA.Wait();
16 
17           Console.WriteLine(4);
18 
19       }
20 
21       catch (AggregateException)
22 
23       {
24 
25           Console.WriteLine("Exception in taskA.");
26 
27       }
28 
29       Console.WriteLine(5);
30 
31       Console.Read();
32 
33   }

 

 

首先main输出 1和2,然后此时插入任务taskA。它在休眠2秒后,输出3,然后任务结束后输出4,最后main中输出5。

任务taskA执行完毕后大概需要2秒钟的时间,这样,如果不等待taskA,即taskA启动执行后,不等待执行完毕,则会执行输出  4和5。

最终打印结果是:1,2,4,5,3(顺序是这样的,但格式是带回车的)

如果进行等待,Wait() 不带参数,表示一直等待到任务执行完毕。

这样,就可以按顺序输出了,最终结果是:1,2,3,4,5

同样的Task类有对应的泛型类型,这里不演示了。

 

await

msdn: https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/await

 

await运算符用于异步方法中的任务,在方法的执行中插入挂起点,直到所等待的任务完成。仅可用于由async关键字修改的异步方法中。

应用await运算符的任务通常由实现基于任务的异步模式的方法调用返回。包括:Task,Task<TResult>,ValueTask 和ValueTask<TResult> 对象的方法。

 

async

msdn: https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/async

 

async修饰符可将方法、lambda表达式,匿名方法指定为异步,带此修饰符的方法或表达式称为异步方法。

 

Msdn上一个非常好的例子:它是有顺序的执行任务,这样通过await达到同步的结果,

https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/index

posted on 2019-06-27 10:47  梅桦  阅读(258)  评论(0编辑  收藏  举报