传统的异步编程来改善程序的响应
上面部分我们已经看到同步方法所带来的实际问题了,为了解决类似的问题,.NET Framework很早就提供了对异步编程的支持,下面就用.NET 1.0中提出的异步编程模型(APM)来解决上面的问题,具体代码如下(注释的部分通过获得GUI线程的同步上文对象,然后同步调用同步上下文对象的post方法把要调用的方法交给GUI线程去处理,因为控件本来就是由GUI线程创建的,然后由它自己执行访问控件的操作就不存在跨线程的问题了,程序中使用的是调用RichTextBox控件的Invoke方式来异步回调访问控件的方法,其实背后的原来和注释部分是一样的,调用RichTextBox控件的Invoke方法可以获得创建RichTextBox控件的线程信息(也就是前一种方式的同步上下文),然后让Invoke回调的方法在该线程上运行):
private void btnClick_Click(object sender, EventArgs e)
{
this.richTextBox1.Clear();
btnClick.Enabled = false;
AsyncMethodCaller caller = new AsyncMethodCaller(TestMethod);
IAsyncResult result = caller.BeginInvoke(GetResult, null);
//// 捕捉调用线程的同步上下文派生对象
//sc= SynchronizationContext.Current;
}
# region 使用APM实现异步编程
// 同步方法
private string TestMethod()
{
// 模拟做一些耗时的操作
// 实际项目中可能是读取一个大文件或者从远程服务器中获取数据等。
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
}
return "点击我按钮事件完成";
}
// 回调方法
private void GetResult(IAsyncResult result)
{
AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;
// 调用EndInvoke去等待异步调用完成并且获得返回值
// 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成
string resultvalue = caller.EndInvoke(result);
//sc.Post(ShowState,resultvalue);
richTextBox1.Invoke(showStateCallback, resultvalue);
}
// 显示结果到richTextBox
private void ShowState(object result)
{
richTextBox1.Text = result.ToString();
btnClick.Enabled = true;
}
// 显示结果到richTextBox
//private void ShowState(string result)
//{
// richTextBox1.Text = result;
// btnClick.Enabled = true;
//}
#endregion
运行的结果为:

C# 5.0 提供的async和await使异步编程更简单
上面部分演示了使用传统的异步编程模型(APM)来解决同步代码所存在的问题,然而在.NET 2.0,.NET 4.0和.NET 4.5中,微软都有推出新的方式来解决同步代码的问题,他们分别为基于事件的异步模式,基于任务的异步模式和提供async和await关键字来对异步编程支持。关于前两种异步编程模式,在我前面的文章中都有介绍,大家可以查看相关文章进行详细地了解,本部分就C# 5.0中的async和await这两个关键字如何实现异步编程的问题来给大家介绍下。下面通过代码来了解下如何使用async和await关键字来实现异步编程,并且大家也可以参看前面的博客来对比理解使用async和await是异步编程更简单。










