假设我有一项服务,它将进行长时间,昂贵的同步操作,即
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。
问题:
答案 0 :(得分:1)
长时间运行的非IO绑定的同步操作不属于ThreadPool。在ThreadPool中运行此类操作会使您面临饥饿的风险,其中池不会足够快地启动线程以响应依赖它的许多其他API的需求。
如果你想运行一些冗长的东西,可以在自己的线程上运行它,如果需要在某个UI中显示,请小心将结果反馈回正确的上下文。
因此,您的第一种方法似乎更合适。
另一方面,TPL提供了提示任务长期运行的机会,并允许系统决定运行它的最佳位置。它很简单:
Task.Factory.StartNew(someSyncAction, TaskCreationOptions.LongRunning)
StartNew
返回一个任务。你可以等待它。