假设我有一项服务将进行长时间、昂贵的同步操作,即
class ExclamationMarkService
{
public string GetData(string param)
{
Thread.Sleep(5000);
return param + "!";
}
}
要通过 EAP 模式将其包装为异步,我可以这样做:
class ExclamationMarkServiceEAP
{
public delegate void GetDataHandler(string data);
public event GetDataHandler GetDataCompleted;
public void GetDataWorker(object param)
{
var service = new ExclamationMarkService();
string data = service.GetData((string)param);
if (GetDataCompleted != null)
{
GetDataCompleted(data);
}
}
public void GetData(string param)
{
var thread = new Thread(GetDataWorker) {IsBackground = true};
thread.Start(param);
}
}
与新的 async/await 运算符类似的事情可以通过这种方式完成:
class ExclamationMarkServiceTaskAsync
{
public async Task<string> GetDataAsync(string param)
{
var service = new ExclamationMarkService();
return await Task.Run(() => service.GetData(param));
}
}
用法:
public static void CallExclamationMarkServiceEAP()
{
var service = new ExclamationMarkServiceEAP();
service.GetDataCompleted += service_GetDataCompleted;
service.GetData("hello EAP");
}
static void service_GetDataCompleted(string data)
{
Console.WriteLine(data);
}
public static async void CallExclamationMarkServiceTaskAsync()
{
var service = new ExclamationMarkServiceTaskAsync();
var data = await service.GetDataAsync("hello TaskAsync");
Console.WriteLine(data);
}
static void Main(string[] args)
{
CallExclamationMarkServiceEAP();
CallExclamationMarkServiceTaskAsync();
Console.Read();
}
在这两种情况下,我都设法将工作转移到后台。在 EAP 的情况下,通过显式启动一个线程。对于 async/await 版本,使用 Task.Run。
问题:
- 我的 ExclamationMarkService 的 APM 实现会是什么样子?
- 给定 EAP 和 APM 版本,如何使用 Task 类的现有方法(Task.Factory.StartNew / Task.Factory.FromAsync 等)来包装它们,以便它们可以与 async/await 关键字一起使用。