大多数时候,我们写的代码都是同步代码,也就是从上到下按照顺序执行。但有时候遇到耗时较多的任务时,同步方法的弊端往往就会显现出来。例如下载一个较大的文件,如果采用同步代码,那么直到这个文件下载完成之前,我们都无法进行任何操作,这就带来了较差的用户体验。这种情况下就得异步方法出马了。在C#中,Delegate
类包含Invoke
和BeginInvoke
两个方法,其中Invoke
是同步的,而BeginInvoke
则是异步的。先看一段代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public delegate void DoWorkHandler();
class Program
{
static void Main(string[] args)
{
Console.WriteLine("开始烧水了");
// 一直等到水烧开
DoWorkHandler handler = (() =>
{
Thread.Sleep(5000);
Console.WriteLine("水烧好了");
});
handler.Invoke();
// 在水未烧开之前一直会有阻塞
Console.WriteLine("扫一下地吧");
}
}
}
运行结果如下:
上面的代码描述的是一个烧水的过程,Thread.Sleep(5000)
模拟一个耗时操作,例如把水烧开花了5秒钟。这时如果调用Invoke方法,由于Invoke
是同步的,线程就会被阻塞,即:在水没有烧开之前我们无法进行其他任何操作。而一般情况下,我们习惯于在烧水的同时还做一些其他的事情,以此提高工作效率和时间利用率,例如在水没有烧开之前,我们可以扫扫地、做做饭之类的。如果要实现一边烧水一边做其他事情,那么就需要用到BeginInvoke
方法。看下面一段代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public delegate void DoWorkHandler();
class Program
{
static void Main(string[] args)
{
Console.WriteLine("开始烧水了");
// 水正在烧
DoWorkHandler handler = (() =>
{
Thread.Sleep(5000);
Console.WriteLine("水烧好了");
});
// 这里不会有阻塞,我们可以做一些其他事情
IAsyncResult asyncResult = handler.BeginInvoke(null, null);
while (!asyncResult.IsCompleted)
{
Console.WriteLine("水还没烧好,先干点其的他事情吧");
Thread.Sleep(1000);
}
// 水烧好了
handler.EndInvoke(asyncResult);
}
}
}
运行结果如下:
可以看到BeginInvoke
并没有阻塞线程,即:在水没有烧好的时间段里,我们可以做一些其他事情。但需要注意,如果EndInvoke
没有执行完,线程依旧会阻塞。现在对上面的代码修改一下,改为回调方式,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public delegate void DoWorkHandler();
class Program
{
static void Main(string[] args)
{
Console.WriteLine("开始烧水了");
// 水正在烧
DoWorkHandler handler = (() =>
{
Thread.Sleep(5000);
Console.WriteLine("水烧好了");
});
// 异步回调
IAsyncResult asyncResult = handler.BeginInvoke(new AsyncCallback(CallBack), null);
while (!asyncResult.IsCompleted)
{
Console.WriteLine("水还没烧好,先干点其的他事情吧");
Thread.Sleep(1000);
}
}
static void CallBack(IAsyncResult result)
{
DoWorkHandler handler = (result as AsyncResult).AsyncDelegate as DoWorkHandler;
handler.EndInvoke(result);
}
}
}
运行结果如下:
上述三种方法更推荐使用回调方法~