近来在学习Eugene Agafonov编写的《C#多线程编程实战》(译),做些笔记也顺便分享一下^-^
本例将讲述使用异步函数的基本场景,比较使用TPL和使用await操作符获取异步操作结果的不同之处。
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Dynamic;
using System.Runtime.CompilerServices;
using ImpromptuInterface;
namespace 对动态类型使用await
{
class Program
{
static void Main(string[] args)
{
Task t = AsynchronousProcessing();
t.Wait();
Console.ReadKey();
}
public interface IAwaiter<T> : INotifyCompletion
{
bool IsCompleted { get; }
T GetResult();
}
static string GetInfo()
{
return string.Format("Task is running on a thread id {0}.Is thread pool thread: {1}",
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
}
static dynamic GetDynamicAwaitableObject(bool completeSynchronously)
{
dynamic result = new ExpandoObject();
dynamic awaiter = new ExpandoObject();
awaiter.Message = "Completed synchronously";
awaiter.IsCompleted = completeSynchronously;
awaiter.GetResult = (Func<string>)(() => awaiter.Message);
awaiter.OnCompleted = (Action<Action>)(callback =>
{
ThreadPool.QueueUserWorkItem(state =>
{
Thread.Sleep(TimeSpan.FromSeconds(1));
awaiter.Message = GetInfo();
if (callback != null)
{
callback();
}
});
});
IAwaiter<string> proxy = Impromptu.ActLike(awaiter);
result.GetAwaiter = (Func<dynamic>)(() => proxy);
return result;
}
async static Task AsynchronousProcessing()
{
string result = await GetDynamicAwaitableObject(true);
Console.WriteLine(result);
result = await GetDynamicAwaitableObject(false);
Console.WriteLine(result);
}
}
}
程序运行结果如下
当程序运行时运行了两个异步操作。其中一个是标准的TPL模式的代码,第二个使用了C#的新特性async和await。AsynchronyWithTPL方法启动了一个任务,运行两秒后返回关于工作线程信息的字符串。然后我们定义了一个后续操作,用于在异步操作完成后打印出该操作结果,还有另一个后续操作,用于万一有错误发生时打印出异常的细节。最终,返回了一个代表其中一个后续操作任务的任务,并等待其在Main函数中完成。
在AsynchronyWithAwait方法中,我们对任务使用await并得到了相同的结果。这和编写通常的同步代码的风格一样,即我们获取任务的结果,打印出结果,如果任务完成时带有错误则捕获异常。关键不同的是这实际上是一个异步程序。使用await后,C#立即创建了一个任务,其有一个后续操作任务,包含了await操作符后面的所有剩余代码。这个新任务也处理了异常传播。然后,将该任务返回到主方法中并等待其完成。