1、使用委托的BeginInvoke和EndInvoke实现异步。
public delegate string ShowName();
static void Main(string[] args)
{
ShowName showName = new ShowName(() => { Console.WriteLine("开始起名字"); Thread.Sleep(3000); Console.WriteLine("名字起好了"); return "名字:李磊"; });
IAsyncResult iAsyncResult = showName.BeginInvoke(null, null);
Console.WriteLine("等待名字或者干点其他的事情。");
Console.WriteLine(showName.EndInvoke(iAsyncResult));
Console.WriteLine("好名字");
Console.ReadLine();
}
结果:
上述过程中只有等EndInvoke执行完成后其实就是等着委托执行完成后才会执行Console.WriteLine("好名字");但是Console.WriteLine("等待名字或者干点其他的事情。");是在BeginInvoke之前就执行了。
下面解决因为EndInvoke造成的阻塞,那就是异步回调。在回调里面调用EndInvoke。为什么非要EndInvoke呢一是获取委托的返回值,二据说是防止内存泄漏。
ShowName showName = new ShowName(() => { Console.WriteLine("开始起名字"); Thread.Sleep(3000); Console.WriteLine("名字起好了"); return "名字:李磊"; });
//做一个回调
AsyncCallback callBack = new AsyncCallback((IAsyncResult iAsyncResult) =>
{
ShowName showNameFun = (ShowName)((AsyncResult)iAsyncResult).AsyncDelegate;
Console.WriteLine(showNameFun.EndInvoke(iAsyncResult));
Console.WriteLine("好名字");
});
showName.BeginInvoke(callBack, null);
Console.WriteLine("等待名字或者干点其他的事情。");
Thread.Sleep(1000);
Console.WriteLine("名字还没起好?");
调用BeginInvoke之后会继续向下进行不会阻塞,当委托执行完成后会调用回调,在回调中获取了委托的返回值。
结果如下:
2、Task异步
Task<string> task= Task.Run(() => { Console.WriteLine("开始起名字"); Thread.Sleep(3000); Console.WriteLine("名字起好了"); return "名字:李磊"; });
Console.WriteLine("等待名字或者干点其他的事情。");
Thread.Sleep(1000);
Console.WriteLine("名字还没起好?");
结果:
发现一直没有return "名字:李磊";这个返回值。因为没有获取,如果需要获取就需要。
同样的发现task.Result阻塞了线程。和EndInvoke差不多。
3、async和await的异步
static void Main(string[] args)
{
ShowNameAsync();
Console.WriteLine("等待名字或者干点其他的事情。");
Thread.Sleep(1000);
Console.WriteLine("名字还没起好?");
}
static async Task ShowNameAsync()
{
string name = await Task.Run(() => { Console.WriteLine("开始起名字"); Thread.Sleep(3000); Console.WriteLine("名字起好了"); return "名字:李磊"; });
Console.WriteLine(name);
return;
}
结果:
没有阻塞线程,异步方法的返回值据说建议使用Task代替void。还有async和await据说要配对使用。还有异步方法名称最好Async结尾。
最后,配合WPF中的属性绑定会将耗时数据加载呈现出不错的用户体验。