如何使用任务有条不紊地运行代码

我有一个负责检索资源的课程,这些课程也会对它们进行快速访问。 该类公开了一种用于检索资源的异步方法:

public Task GetResourceAsync(string resourceName) { return Task.Factory.StartNew(() => { // look in cache // if not found, get from disk // return resource }); } 

然后客户端代码如下所示:

 myResourceProvider.GetResourceAsync("myResource") .ContinueWith(t => Console.WriteLine("Got resource " + t.Result.ToString())); 

这样,始终使用后台线程。 但是,如果在缓存中找到对象,我不希望代码异步运行。 如果在缓存中找到它,我想立即返回资源而不必使用另一个线程。

谢谢。

.NET 4.5具有Task.FromResult ,它允许您返回Task ,但它不是在线程池线程上运行委托,而是显式设置任务的返回值。

所以在你的代码的上下文中:

 public Task AsyncGetResource(string resourceName) { object valueFromCache; if (_myCache.TryGetValue(resourceName, out valueFromCache)) { return Task.FromResult(valueFromCache); } return Task.Factory.StartNew(() => { // get from disk // add to cache // return resource }); } 

如果您仍在使用.NET 4.0,则可以使用TaskCompletionSource执行相同的操作:

 var tcs = new TaskCompletionSource(); tcs.SetResult(...item from cache...); return tcs.Task; 

如果您有UI连接线程,请小心。

在WPF中,非常重要的是,在UI线程上使用Task.Run(例如,按钮单击事件处理程序),以避免UI问题,并在后台线程上运行代码。

为什么? Task.Run默认情况下是一个包​​装Task.Factory.StartNew的包装器,带有TaskScheduler.Default参数,而不是TaskScheduler.Current。

所以仅仅调用这样的异步方法还不够,因为这是在UI线程上运行并冻结它: await SomeTaskAsync();

而不是它你应该在Task.Run中调用它:

  • Task.Run(async() => await SomeTaskAsync());

或者在Task.Run中使用syncron方法:

  • Task.Run(() => SomeTask());