住宅小区物业管理系统网站建设,青之峰网站建设,做外卖有哪些网站,上哪里建设个人网站摘要
异步这东西#xff0c;真正用起来的时候#xff0c;发现事情还是挺多的#xff0c;最近在项目中用到了异步的知识#xff0c;发现对它还是不了解#xff0c;处理起来#xff0c;走了不少弯路。觉得还是补一补还是很有必要的。
MSDN原文地址#xff1a;https://ms…摘要
异步这东西真正用起来的时候发现事情还是挺多的最近在项目中用到了异步的知识发现对它还是不了解处理起来走了不少弯路。觉得还是补一补还是很有必要的。
MSDN原文地址https://msdn.microsoft.com/en-us/library/2e08f6yc(vvs.110).aspx
正文
.Net framework可以让你异步调用任何方法。为达到这样的目的你可以定义一个与你要调用的方法的签名相同的委托。公共语言运行时将自动为该委托定义与签名相同的BeginInvok和EndInvoke方法。
异步的委托调用方法BeginInvok和EndInvoke在.NET Compact Framework中并没有得到支持。
BeginInvoke方法触发你的异步方法它和你想要执行的异步方法有相同的参数。另外还有两个可选参数第一个是AsyncCallback委托是异步完成的回调方法。第二个是用户自定义对象该对象将传递到回调方法中。BeginInvoke立即返回并且不等待完成异步的调用继续执行该方法调用下面的代码不需要等待。BeginInvoke返回IAsyncResult接口可用于检测异步调用方法线程的状态。
通过EndInvoke方法检测异步调用的结果。如果异步调用尚未完成EndInvoke将阻塞调用线程直到它完成。EndInvoke参数包括out和ref参数。
下面代码演示使用BeginInvoke和EndInvoke进行异步调用的四种常见方式。在调用BeginInvoke可以做以下工作
做一些其他操作然后调用EndInvoke方法阻塞线程直到该方法完成。使用IAsyncResult.AsyncWaitHandle属性使用它的WaitOne方法阻塞线程直到收到WaitHandle信号然后调用EndInvoke。检查BeginInvoke返回值IAsyncResult的状态来决定方法是否完成然后调用EndInvoke方法。通过在BeginInvoke方法中传递该委托在回调方法中调用该委托的EndInvoke方法。
注意
无论你怎么使用都必须调用EndInvoke方法结束你的异步调用。
下面通过模拟一个耗时的操作实现上面说的那四种情况。
情况一通过EndInovke阻塞线程直到异步调用结束。
using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// summary/// 委托必须和要调用的异步方法有相同的签名/// /summary/// param namecallDurationsleep时间/param/// param namethreadId当前线程id/param/// returns/returnspublic delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// summary/// 主函数/// /summary/// param nameargs/paramstatic void Main(string[] args){AsyncMethodCaller caller new AsyncMethodCaller(TestMethodAsync);int threadid 0;//开启异步操作IAsyncResult result caller.BeginInvoke(3000, out threadid, null, null);for (int i 0; i 10; i){Console.WriteLine(其它业务 i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine(等待异步方法TestMethodAsync执行完成);string res caller.EndInvoke(out threadid, result);Console.WriteLine(Completed!);Console.WriteLine(res);Console.Read();}/// summary/// 与委托对应的方法/// /summary/// param namecallDuration/param/// param namethreadId/param/// returns/returnsstatic string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw new Stopwatch();sw.Start();Console.WriteLine(异步TestMethodAsync开始);for (int i 0; i 5; i){ // 模拟耗时操作Thread.Sleep(callDuration);Console.WriteLine(TestMethodAsync: i.ToString());}sw.Stop();threadId Thread.CurrentThread.ManagedThreadId;return string.Format(耗时{0}ms., sw.ElapsedMilliseconds.ToString());}}
}结果
由上图可以看出在BeginInvoke开启异步执行方法会先执行其他的业务。通过EndInvoke方法阻塞直到异步执行完毕才会执行EndInvoke之后的代码。
情况二通过WaitHandle属性阻塞线程。
你可以获得BeginInvoke的返回值的WaitHandle并使用它的AsyncWaitHanlde属性。WaitHandle信号异步完成时你可以通过调用WaitOne方法等待。
如果你使用WaitHandle你可以在之前或者异步调用完成后进行其他的操作。但之后必须使用EndInvoke检查结果。
注意
当你调用EndInvoke方法时等待句柄并不会自动关闭。如果你释放等待处理的所有引用当垃圾回收等待句柄是系统资源将被释放。一旦你完成使用等待句柄通过WaitHandle的close方法一次性显示关闭这时的垃圾回收效率更高。~
using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// summary/// 委托必须和要调用的异步方法有相同的签名/// /summary/// param namecallDurationsleep时间/param/// param namethreadId当前线程id/param/// returns/returnspublic delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// summary/// 主函数/// /summary/// param nameargs/paramstatic void Main(string[] args){AsyncMethodCaller caller new AsyncMethodCaller(TestMethodAsync);int threadid 0;//开启异步操作IAsyncResult result caller.BeginInvoke(3000, out threadid, null, null);for (int i 0; i 10; i){Console.WriteLine(其它业务 i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine(等待异步方法TestMethodAsync执行完成);//等待异步执行完毕信号result.AsyncWaitHandle.WaitOne();Console.WriteLine(收到WaitHandle信号);//通过EndInvoke检查结果string res caller.EndInvoke(out threadid, result);//显示关闭句柄result.AsyncWaitHandle.Close();Console.WriteLine(关闭了WaitHandle句柄);Console.WriteLine(Completed!);Console.WriteLine(res);Console.Read();}/// summary/// 与委托对应的方法/// /summary/// param namecallDuration/param/// param namethreadId/param/// returns/returnsstatic string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw new Stopwatch();sw.Start();Console.WriteLine(异步TestMethodAsync开始);for (int i 0; i 5; i){ // 模拟耗时操作Thread.Sleep(callDuration);Console.WriteLine(TestMethodAsync: i.ToString());}sw.Stop();threadId Thread.CurrentThread.ManagedThreadId;return string.Format(耗时{0}ms., sw.ElapsedMilliseconds.ToString());}}
}输出
情况三检查BeginInvoke返回结果的状态。
可以通过BeginInvoke的返回结果的IsCompleted属性检查异步是否完成。你可以在异步没有完成的时候做其他的操作。
View Code 输出
复制代码 其它业务0 其它业务1 其它业务2 其它业务3 其它业务4 其它业务5 其它业务6 其它业务7 其它业务8 其它业务9 等待异步方法TestMethodAsync执行完成 异步TestMethodAsync开始 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… TestMethodAsync:0 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… TestMethodAsync:1 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… TestMethodAsync:2 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… TestMethodAsync:3 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… 异步方法running… TestMethodAsync:4 异步方法running… 关闭了WaitHandle句柄 Completed! 耗时5031ms. 复制代码
情况四通过在回调方法中。
如果需要在异步完成后需要做一些其他的操作你可以在异步完成时执行一个回调方法。在该回调方法中做处理。
首先需要定义一个回调方法。
using System;
using System.Diagnostics;
using System.Threading;namespace BeginInvokeDemo
{/// summary/// 委托必须和要调用的异步方法有相同的签名/// /summary/// param namecallDurationsleep时间/param/// param namethreadId当前线程id/param/// returns/returnspublic delegate string AsyncMethodCaller(int callDuration, out int threadId);class Program{/// summary/// 主函数/// /summary/// param nameargs/paramstatic void Main(string[] args){AsyncMethodCaller caller new AsyncMethodCaller(TestMethodAsync);int threadid 0;//开启异步操作IAsyncResult result caller.BeginInvoke(1000, out threadid, callBackMethod, caller);for (int i 0; i 10; i){Console.WriteLine(其它业务 i.ToString());}//调用EndInvoke,等待异步执行完成Console.WriteLine(等待异步方法TestMethodAsync执行完成);//等待异步执行完毕信号//result.AsyncWaitHandle.WaitOne();//Console.WriteLine(收到WaitHandle信号);//通过循环不停的检查异步运行状态//while (result.IsCompletedfalse)//{// Thread.Sleep(100);// Console.WriteLine(异步方法running........);//}//异步结束拿到运行结果//string res caller.EndInvoke(out threadid, result);显示关闭句柄//result.AsyncWaitHandle.Close();Console.WriteLine(关闭了WaitHandle句柄);//Console.WriteLine(res);Console.Read();}/// summary/// 异步方法回调方法,异步执行完毕会回调该方法/// /summary/// param namear/paramprivate static void callBackMethod(IAsyncResult ar){AsyncMethodCaller caller ar.AsyncState as AsyncMethodCaller; string result caller.EndInvoke(out int threadid, ar);Console.WriteLine(Completed!);Console.WriteLine(result);}/// summary/// 与委托对应的方法/// /summary/// param namecallDuration/param/// param namethreadId/param/// returns/returnsstatic string TestMethodAsync(int callDuration, out int threadId){Stopwatch sw new Stopwatch();sw.Start();Console.WriteLine(异步TestMethodAsync开始);for (int i 0; i 5; i){ // 模拟耗时操作Thread.Sleep(callDuration);Console.WriteLine(TestMethodAsync: i.ToString());}sw.Stop();threadId Thread.CurrentThread.ManagedThreadId;return string.Format(耗时{0}ms., sw.ElapsedMilliseconds.ToString());}}
}总结
在项目中遇到的有参数又返回值的情况如何在回调方法中拿到委托和传递的参数当时卡这里了后来查看情况四的情况才得以解决。这里也再学习一下。
博客地址http://www.cnblogs.com/wolf-sun/ #3楼 2018-05-23 16:56 LaTiao 不知道是我理解有问题还是别的情况,如果按照下面方法调用其实是需要等到函数执行完毕才会向下执行的,这种情况看起来并不是异步,代码:
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
static void Main(string[] args)
{
Console.WriteLine(11);
Test();
Console.WriteLine(22);
}
static void Test()
{
int threadId;
AsyncMethodCaller caller new AsyncMethodCaller(TestMethod);
IAsyncResult result caller.BeginInvoke(3000, out threadId, null, null);
Thread.Sleep(0);
Console.WriteLine(Main thread {0} does some work., Thread.CurrentThread.ManagedThreadId);
//等待WaitHandle信号
result.AsyncWaitHandle.WaitOne();
//调用EndInvoke方法等待异步嗲用完成并得到结果。
string returnValue caller.EndInvoke(out threadId, result);
//关闭等待句柄
result.AsyncWaitHandle.Close();
Console.WriteLine(The call executed on thread {0},with return value {1}., threadId, returnValue);
}输出结果: 11 Main thread 9 does some work. Test method begins: The call executed on thread 10,with return value My call time was 3000… 22
我认为22应该打印在Main thread 9 does some work.之后,才叫异步,比如代码如下:
static AsyncMethodCaller caller;
static void Main(string[] args)
{
caller new AsyncMethodCaller(TestMethod);
Console.WriteLine(1);
Test();
Console.WriteLine(2);
Console.Read();
}
static void Test()
{
int dummy 0;
IAsyncResult result caller.BeginInvoke(3000, out dummy, AsyncCallbackImpl, The call executed on thread {0},with return value {1}.);
Console.WriteLine( *-*-* );
}static void AsyncCallbackImpl(IAsyncResult ar)
{
int dummy 0;string re caller.EndInvoke(out dummy, ar);Console.WriteLine( *** re ar.AsyncState);
}
static string TestMethod(int callDuration, out int threadId)
{
Console.WriteLine(Test method begins:);
//睡一会 模拟耗时操作
Thread.Sleep(callDuration);
threadId Thread.CurrentThread.ManagedThreadId;
return string.Format(My call time was {0}., callDuration.ToString());
}输出结果如下: 1 --* 2 Test method begins: *** My call time was 3000.The call executed on thread {0},with return value {1}. 不过有个问题就是这样拿到的返回值很难用
#4楼 [楼主] 2018-05-25 11:31 wolfy LaTiao //等待WaitHandle信号 result.AsyncWaitHandle.WaitOne(); //调用EndInvoke方法等待异步嗲用完成并得到结果。 string returnValue caller.EndInvoke(out threadId, result);
这种方式通过waiteone阻塞了是为了拿到异步的返回值。 一般endinvoke 用在beginInvoke的回调函数中。但如果想在同一个方法中拿到返回值可以采用这种方式。
支持(0) 反对(0) #5楼 [楼主] 2018-05-25 13:18 wolfy LaTiao 有可能给的demo描述的不太清楚我把demo重新修改了下更有助于理解希望对你有所帮助 支持(0) 反对(0) #6楼 2019-05-09 16:32 雨落忧伤 由上图可以看出在BeginInvoke开启异步执行方法会先执行其他的业务。通过EndInvoke方法阻塞直到异步执行完毕才会执行EndInvoke之后的代码。
请问 为什么会先 执行其他的业务 而不是一起执行 如果 其他的业务 到 EndInvoke 之间 要花大量时间的处理 异步是不是会一直等待执行完了 再执行自己的异步方法