防止BeginInvoke阻塞

本文介绍如何使用IAsyncResult.IsCompleted属性来检查异步调用的状态,避免使用等待或阻塞的方式。通过示例代码展示了如何在模拟工作的轮询模式中不断检查IsCompleted属性,直至异步操作完成。

用IAsyncResult.IsCompleted 属性可以不用通过等待或阻塞的方式来得到调用的状态。

因此,可以在严格的轮询模式中使用IsCompleted属性:

 

<think>我们正在讨论的是.NET中的异步编程,特别是BeginInvoke方法的使用。根据引用的内容,BeginInvoke是委托类型的一个方法,用于启动异步操作。下面将结合引用内容详细介绍BeginInvoke的用法和概念。引用[1]提到:当我们调用委托的BeginInvoke方法时,它开始在一个独立线程上执行引用方法。并且立即返回到原始线程。原始线程可以继续。而引用方法会在线程池中的线程中并行执行。因此,BeginInvoke的基本用法是:1.定义一个委托,该委托指向一个方法。2.使用该委托实例调用BeginInvoke方法,传入方法所需的参数以及两个可选参数:一个异步回调函数和一个状态对象。3.BeginInvoke会立即返回一个IAsyncResult对象,该对象用于监控异步操作的进度和状态。引用[2]描述了轮询模式:在轮询模式中,原始线程发起了异步方法的调用,做一些其它处理,然后使用IAsyncResult对象的IsCompleted属性来定期检查开启的线程是否完成。另外,引用[5]展示了一个代码示例,其中使用了BeginInvoke和EndInvoke。注意,在调用BeginInvoke后,我们需要调用EndInvoke来获取异步操作的结果(如果有的话),并且EndInvoke会阻塞直到异步操作完成。步骤详解:1.定义委托和方法:首先需要一个委托类型,并且有与之匹配的方法。例如,引用[4]中展示了一个自定义的AsyncEventHandler委托,它有BeginInvoke和EndInvoke方法。但实际上,当我们定义任何委托时,编译器会自动生成这些方法。2.调用BeginInvoke:在委托实例上调用BeginInvoke,传递方法参数、回调函数和状态对象。例如:```csharpAsyncTesttest=newAsyncTest();SalaryEventHandlerdele=test.YearlySalary;IAsyncResultasyncResult=dele.BeginInvoke(100000,15,100000,null,null);```这里的参数100000,15,100000对应委托方法YearlySalary的参数。3.异步操作进行中:此时,我们可以在主线程继续工作。4.获取结果:通过EndInvoke来获取结果。如引用[5]所示,可以通过IAsyncResult获取到原始的委托,然后调用EndInvoke:```csharpAsyncResultresult=(AsyncResult)asyncResult;SalaryEventHandlersalDel=(SalaryEventHandler)result.AsyncDelegate;decimalval=salDel.EndInvoke(asyncResult);```或者直接使用委托实例调用EndInvoke(推荐):```csharpdecimalval=dele.EndInvoke(asyncResult);```注意:EndInvoke会一直阻塞,直到异步操作完成。5.其他模式:除了轮询(IsCompleted)外,还可以使用回调函数(AsyncCallback)在异步操作完成时自动调用一个方法,在那个方法中调用EndInvoke。需要注意的是,滥用异步可能会影响性能和增加编程难度[^3]。下面是一个简单的示例,展示使用BeginInvoke和EndInvoke的基本步骤:```csharpusingSystem;usingSystem.Threading;classProgram{//定义委托publicdelegateintCalculateDelegate(inta,intb);staticvoidMain(){CalculateDelegatecalc=newCalculateDelegate(Calculate);//启动异步调用IAsyncResultresult=calc.BeginInvoke(5,10,null,null);//主线程执行其他任务Console.WriteLine("主线程继续工作...");//模拟工作Thread.Sleep(1000);//获取异步操作结果intsum=calc.EndInvoke(result);Console.WriteLine("计算结果:"+sum);}staticintCalculate(inta,intb){//模拟长时间计算Thread.Sleep(2000);returna+b;}}```在上面的代码中,BeginInvoke启动了一个异步操作,它调用Calculate方法,并立即返回。主线程继续执行,最后通过EndInvoke等待异步操作完成并获取结果。注意:在.NETFramework中,BeginInvoke/EndInvoke模式主要用于委托的异步调用。在.NETCore/.NET5+中,这种模式已被Task取代,但了解其原理仍有益处。§§相关问题§§1.BeginInvoke和EndInvoke如何结合使用?2.使用BeginInvoke有哪些风险?3.如何在异步操作完成后使用回调函数?</think> ### BeginInvoke 在 .NET 异步编程中的核心概念 `BeginInvoke` 是 .NET 委托类型提供的异步执行方法,属于 **APM(异步编程模型)** 的核心组件。以下是其核心特性和用法: #### 1️⃣ 工作原理 - **异步启动**:调用 `BeginInvoke` 时,委托方法在**线程池线程**中异步执行 - **非阻塞**:立即返回 `IAsyncResult` 对象,**主线程无需等待** - **执行流程**: ```mermaid graph LR A[主线程调用 BeginInvoke] --> B[创建线程池任务] B --> C[主线程继续执行] B --> D[异步执行委托方法] D --> E[调用 EndInvoke 获取结果] ``` #### 2️⃣ 方法签名 ```csharp public virtual IAsyncResult BeginInvoke( string name, AsyncCallback callback, // 完成时的回调函数 object @object // 自定义状态对象 ); ``` #### 3️⃣ 关键组件 1. **IAsyncResult** 对象: - `IsCompleted`:检查操作是否完成 - `AsyncWaitHandle`:提供同步等待句柄 - `AsyncState`:获取传递的自定义状态 ```csharp if (asyncResult.IsCompleted) { var result = del.EndInvoke(asyncResult); } ``` 2. **EndInvoke**: - **强制阻塞**直到异步操作完成 - **获取返回值**或捕获异常 ```csharp decimal salary = salaryDel.EndInvoke(asyncResult); ``` #### 4️⃣ 使用模式 **轮询模式(推荐)**: ```csharp IAsyncResult result = del.BeginInvoke(params, null, null); while (!result.IsCompleted) { Thread.Sleep(100); // 模拟其他工作 Console.Write("."); } var finalResult = del.EndInvoke(result); // 安全获取结果[^2] ``` **回调模式**: ```csharp del.BeginInvoke(params, ar => { try { var res = del.EndInvoke(ar); Console.WriteLine($"结果: {res}"); } catch (Exception ex) { /* 错误处理 */ } }, null); ``` #### 5️⃣ 注意事项 1. **必须调用 EndInvoke** 以防止资源泄漏 2. 参数传递需考虑**线程安全性** 3. 异步操作中异常会延迟到 `EndInvoke` 时抛出 4. 现代 .NET 推荐使用 **Task-based 异步模式(TAP)** 替代 > ⚠️ **重要限制**:在 .NET Core 3.0+ 中,`BeginInvoke/EndInvoke` **不再支持**普通委托,仅用于特定场景[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值