目录
一、什么是异步编程
二、await和async
三、异步方法不等于多线程
四、IAsyncResult接口
五、四种异步编程方法
一、什么是异步编程
这些年.Net增加了很多新特性,其中一个特性就是异步编程,因为.Net的异步编程模型把复杂的异步编程变得简单易用。使得开发人员可以轻松开发出更高效的应用程序。使用 .NET 异步编程,在程序继续执行的同时对 .NET 类方法进行调用,直到进行指定的回调为止;或者如果没有提供回调,则直到对调用的阻塞、轮询或等待完成为止。异步编程的优点就是可以提高服务器接待请求的数量,但不会使得单个请求的处理效率变高,甚至有可能略有降低,
二、await和async
在NETCore 中成为主流用法用async关键字修饰方法后,这个方法就成了“异步方法”。异步方法有如下几点需要注意
(1)异步方法的返回值一般是 Task<T>泛型类型,其中的T是真正的返回值类型,比如方法想要返回 int类型,返回值就要写成 Task<int>。Task 类型定义在 System.Threading.Tasks 命名空间下。
(2)按照约定,异步方法的名字以 Async 结尾,虽然这不是语法的强制要求,但是方法以Async结尾可以让开发人员一眼就看出来它是异步方法。
(3)如果异步方法没有返回值,可以把返回值声明为 void,这在语法上是成立的。但这样的代码在使用的时候有很多的问题,而且很多框架都要求异步方法的返回值不能为 void,因此即使方法没有返回值,也最好把返回值声明为非泛型的 Task类型。
(4)调用泛型方法的时候,一般在方法前加上 await 关键字,这样方法调用的返回值就是泛型指定的T类型的值。
(5)一个方法中如果有await调用,这个方法也必须修饰为async,异步方法有传染性
三、异步方法不等于多线程
using System;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static async Task Main(string []args)
{
Console.WriteLine("之前ID: "+Thread.CurrentThread.ManagedThreadId);
await CalcAsync(5000);
Console.WriteLine("之后: "+Thread.CurrentThread.ManagedThreadId);
}
//n个随机数相加
static async Task<double> CalcAsync(int n)
{
Console.WriteLine("CalcAsync: " + Thread.CurrentThread.ManagedThreadId);
double result = 0;
Random random = new Random();
for(var i = 0; i < n; i++)
result += random.NextDouble();
return result;
}
}
}
线程ID发现并没有变。异步方法并不会自动在新的线程中执行,除非把代码放到新线程中去。有的异步方法没标async,异步方法不要使用Sleep。
四、IAsyncResult接口
IAsyncResult 接口用于监视和管理异步操作。该接口是从开始操作返回的并被传递到结束操作,以将开始操作和结束操作相关联。如果回调被
指定为开始操作的一部分,则 AsyncResult 被传递到回调。它的四个属性如下:
AsyncState :返回在开始操作方法调用中作为最后一个参数提供的对象。
AsyncWaitHandle :返回 WaitHandle,后者可用于执行 WaitHandle.WaitOne、WaitAny 或 WaitAll。
CompletedSynchronously :如果开始操作调用已同步完成,则 CompletedSynchronously 属性将被设置为 true。
IsCompleted :在服务器已处理完调用后,IsCompleted 属性将被设置为 true。
五、四种异步编程方法
调用BeginInvoke后,有四种选择:
(1)进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。
(2)使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出WaitHandle 信号,然后调用 EndInvoke。
(3)轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用EndInvoke。
(4)将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。