假设我有一项服务,该服务将进行漫长而昂贵的同步操作,即
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);
}
}
可以以这种方式完成新的异步/等待运算符的类似事情:
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,通过明确启动线程。对于异步/等待版本,使用task.run。
问题:
- APM的Usplamationmarkservice的实现将如何?
- 给定EAP和APM版本,如何使用任务类的现有方法(task.factory.startnew/task.factory.fromasync等)包裹它们,以便可以与异步/等等一起使用关键字。
不限制的长期运行同步操作不属于线程池。在The Treadpool中运行此类操作会使您面临饥饿的风险,其中池的旋转线程不足以迅速旋转,无法响应许多其他依赖它的API的需求。
如果您想运行一些漫长的东西,请在自己的线程上运行它,如果需要在某些UI中显示,请小心将结果汇回正确的上下文。
因此,您的第一种方法似乎更合适。
另一方面,TPL提供了暗示任务长期运行的机会,并允许系统决定运行它的最佳位置。就像:
一样简单Task.Factory.StartNew(someSyncAction, TaskCreationOptions.LongRunning)
StartNew
返回任务。您可以等待它。