我有一个负责检索资源的课程,这些课程也会对它们进行快速访问。 该类公开了一种用于检索资源的异步方法:
public Task<object> GetResourceAsync(string resourceName)
{
return Task.Factory.StartNew<object>(() =>
{
// look in cache
// if not found, get from disk
// return resource
});
}
客户端代码如下所示:
myResourceProvider.GetResourceAsync("myResource")
.ContinueWith<object>(t => Console.WriteLine("Got resource " + t.Result.ToString()));
这样,总是使用后台线程。但是,如果在缓存中找到对象,我不希望代码异步运行。 如果在缓存中找到它,我想立即返回资源而不必使用另一个线程。
感谢。
答案 0 :(得分:22)
.NET 4.5具有Task.FromResult
,允许您返回Task<T>
,但它不是在线程池线程上运行委托,而是显式设置任务的返回值。
所以在你的代码的上下文中:
public Task<object> AsyncGetResource(string resourceName)
{
object valueFromCache;
if (_myCache.TryGetValue(resourceName, out valueFromCache)) {
return Task.FromResult(valueFromCache);
}
return Task.Factory.StartNew<object>(() =>
{
// get from disk
// add to cache
// return resource
});
}
如果您仍在使用.NET 4.0,则可以使用TaskCompletionSource<T>
执行相同的操作:
var tcs = new TaskCompletionSource<object>();
tcs.SetResult(...item from cache...);
return tcs.Task;
答案 1 :(得分:0)
请注意是否有UI连接线程。
在WPF中,非常重要的一点是,要在UI线程上使用Task.Run(例如,按钮单击事件处理程序),以避免UI问题,并在后台线程上运行代码。
为什么?默认情况下,Task.Run使用TaskScheduler.Default参数而不是TaskScheduler.Current围绕Task.Factory.StartNew进行包装。
仅调用像这样的异步方法还不够,因为它正在UI线程上运行并冻结它:await SomeTaskAsync();
相反,您应该在Task.Run中调用它:
Task.Run(async() => await SomeTaskAsync());
或在Task.Run中使用您的syncron方法:
Task.Run(() => SomeTask());