【.NET Core】深入理解异步编程模型(APM)

【.NET Core】深入理解异步编程模型(APM)

文章目录

一、APM概述

APM英文是Asynchronous Programming Model 是net 1.0时期就提出的一种异步模式,并基于IAsyncResult接口实现Beginxxx和Endxxx的两个方法来实现的,Beginxxx方法是开始异步操作,Endxxx方法是结束异步操作。

在调用Beginxxx后,应用程序可以继续在调用线程上执行指令,同时异步操作在另一个线程上执行。每次调用Beginxxx时,应用程序还应调用Endxxx来获取操作的结果。

c# 复制代码
public class Budget
{
    public delegate string FindBudgetDelegate();
    public string FindBudget() 
    {
        Thread.Sleep(20000);
        return $"2024年财年预算-预算科目编制.";
    }
}

IAsyncResult实现APM

c# 复制代码
static void Main(string[] args)
{
    Budget budget =new Budget();
    Budget.FindBudgetDelegate findBudgetDelegate  =budget.FindBudget;
    IAsyncResult asyncResult =   findBudgetDelegate.BeginInvoke(null,null);
    string response =  findBudgetDelegate.EndInvoke(asyncResult);
    Console.WriteLine(response);
}

二、IAsyncResult接口

接口IAsyncResult由包含可异步操作的方法的类实现。它是启动操作的方法的返回类型。IAsyncResult当异步操作完成时,对象会传递给委托调用AsyncCallback的方法。使用.NET可以以异步方法调用任何方法。首先,需要定义一个委托,该委托具有与调用的方法相同的签名。公共语言运行时将自动用适当的签名为此委托定义BeginInvokeEndInvoke方法。

2.1 BeginInvoke

BeginInvoke方法启动异步调用。该方法具有与你要异步的方法相同的参数,另加两个可选参数。第一个参数是一个AsyncCallBack委托。此委托引用在异步调用完成时要调用的方法。第二个参数是一个用户定义的对象,该对象将信息传递到回调方法。BeginInvoke将立即返回,而不会等待异步调用完成。BeginInvoke返回可用于监视异步调用的进度的IAsyncResult

2.2 EndInvoke

EndInvoke方法用于检索异步调用的结果。它可以在调用BeginInvoke之后的任意时间调用。如果异步调用尚未结束,那么EndInvoke将阻止调用线程,直到完成异步调用。EndInvoke的参数包括要异步执行的方法的outref参数。

2.3 IAsyncResult属性

序号 属性 说明
1 AsyncState 获取一个用户定义的对象,该对象限定或包含有关异步操作的信息
2 AsyncWaitHandle 获取用于等待异步操作完成的WaitHandle
3 CompletedSynchronously 获取一个值,该值指示异步操作是否同步完成
4 IsCompleted 获取一个值,该值指示异步操作是否完成

2.4 IAsyncResult异步演示

c# 复制代码
static void Main(string[] args)
{
     Budget budget =new Budget();
     Budget.FindBudgetDelegate findBudgetDelegate  =budget.FindBudget;
     IAsyncResult asyncResult =   findBudgetDelegate.BeginInvoke(new AsyncCallback(FindOneAsyncCallBack),null);
     Console.WriteLine("BeginInvoke异步开始");
     Console.WriteLine($"当前主线程{Thread.CurrentThread.Name}");
     Console.WriteLine($"Main->{asyncResult.AsyncState}");
     Console.WriteLine("WaitOne");
     Console.ReadKey();
}

static void FindOneAsyncCallBack(IAsyncResult asyncResult) 
{
     Budget.FindBudgetDelegate budgetDelegate =   ((AsyncResult)asyncResult).AsyncDelegate as Budget.FindBudgetDelegate;
     Console.WriteLine(budgetDelegate.EndInvoke(asyncResult));
     Console.WriteLine($"FindOneAsyncCallBack->{asyncResult.AsyncState}");
}

三、通过结束异步操作来阻止应用程序执行

如果应用无法在等待异步操作结果期间继续执行其他工作,必须阻止应用一直到操作完成。可以使用下列方法之一,在应用等待异步操作完成期间阻止应用的主程序:

  • 调用异步操作的EndOperationName方法。
  • 使用异步操作的BeginOperationName方法返回的IAsyncResultAsyncWaitHandle属性。

在异步操作完成前使用EndOperationName方法阻止的应用程序,通常会调用BeginOperationName方法,执行任何不需要等待操作结果也可以执行的工作,然后调用EndOperationName

c# 复制代码
static void Main(string[] args)
{
    Budget budget =new Budget();
    Budget.FindBudgetDelegate findBudgetDelegate  =budget.FindBudget;
    IAsyncResult asyncResult =   findBudgetDelegate.BeginInvoke(null,null);
    string response =  findBudgetDelegate.EndInvoke(asyncResult);
    Console.WriteLine(response);
}

四、使用AsyncWaitHandle阻止应用程序的执行

在异步操作完成前使用一个或多个WaitHandle对象阻止的应用,通常会调用BeginOperationName方法,执行任何不需要等待操作结果也可以执行的工作,并在一个或多个异常操作完成前一直处于阻止状态。可以使用AsyncWaitHandle调用WaitOne方法之一,对单一操作阻止应用。若要在等待一组异步操作完成期间阻止应用,请将关联的AsyncWaitHandle对象存储到数组中,并调用WaitAll方法之一。若要在等待一组异步操作中任一操作完成期间阻止应用。请将关联的AsyncWaitHandle对象存储到数组中,并调用WaitAny方法之一。

c# 复制代码
static void Main(string[] args)
{
    Budget budget =new Budget();
    Budget.FindBudgetDelegate findBudgetDelegate  =budget.FindBudget;
    IAsyncResult asyncResult =   findBudgetDelegate.BeginInvoke(null,null);
    // Wait until the operation completes
    asyncResult.AsyncWaitHandle.WaitOne();
    string response =  findBudgetDelegate.EndInvoke(asyncResult);
    Console.WriteLine(response);
}

五、轮询异步操作的状态

如果应用可以在等待异步操作结果期间继续执行其他工作,不得阻止应用一直到操作完成。请使用下列方法之一,在应用等待异步操作完成期间继续执行指令:

  • 使用返回IAsyncResultIsCompleted属性,确定操作是否已完成。这种方法称为"轮询"。
  • 使用AsyncCallBack委托,在单独的线程中处理异步操作结果。

六、总结

使用委托可通过异步方式调用同步方法。 如果同步调用委托,Invoke 方法将在当前线程上直接调用目标方法。 如果调用 BeginInvoke 方法,公共语言运行时 (CLR) 将对请求进行排队并立即返回给调用方。 目标方法将在线程池中的某个线程上异步调用。 提交请求的原始线程可以不受限制地继续与目标方法并行执行。 如果已在对 BeginInvoke 方法的调用中指定回叫方法,则目标方法结束时,将调用回叫方法。 在回叫方法中,EndInvoke 方法将获取返回值和所有输入/输出或仅输出参数。 如果调用 BeginInvoke 时未指定回叫方法,则可能从调用 BeginInvoke 的线程上调用 EndInvoke

相关推荐
小码编匠5 小时前
一款 C# 编写的神经网络计算图框架
后端·神经网络·c#
小兜全糖(xdqt)7 小时前
.netCore WebAPI中字符串加密与解密
.netcore
沪上百卉7 小时前
.NET Core 常用的三个生命周期
.netcore
Envyᥫᩣ8 小时前
C#语言:从入门到精通
开发语言·c#
假装我不帅13 小时前
asp.net framework从webform开始创建mvc项目
后端·asp.net·mvc
神仙别闹13 小时前
基于ASP.NET+SQL Server实现简单小说网站(包括PC版本和移动版本)
后端·asp.net
IT技术分享社区14 小时前
C#实战:使用腾讯云识别服务轻松提取火车票信息
开发语言·c#·云计算·腾讯云·共识算法
△曉風殘月〆21 小时前
WPF MVVM入门系列教程(二、依赖属性)
c#·wpf·mvvm
逐·風1 天前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#