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

Adi*_*ter 13 .net c# multithreading .net-4.0 task-parallel-library

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

public Task<object> GetResourceAsync(string resourceName)
{
    return Task.Factory.StartNew<object>(() =>
    {
        // look in cache

        // if not found, get from disk

        // return resource
    });
}
Run Code Online (Sandbox Code Playgroud)

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

myResourceProvider.GetResourceAsync("myResource")
    .ContinueWith<object>(t => Console.WriteLine("Got resource " + t.Result.ToString()));
Run Code Online (Sandbox Code Playgroud)

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

谢谢.

Joe*_*ite 23

.NET 4.5 Task.FromResult允许您返回a 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
    });
}
Run Code Online (Sandbox Code Playgroud)

如果你仍然在.NET 4.0上,你可以TaskCompletionSource<T>用来做同样的事情:

var tcs = new TaskCompletionSource<object>();
tcs.SetResult(...item from cache...);
return tcs.Task;
Run Code Online (Sandbox Code Playgroud)

  • 默认情况下调用`Task.Factory.StartNew`使用`TaskScheduler.Current`,这在某些情况下会导致由StartNew启动的任务在UI线程上运行的意外行为.如果您希望代码始终在后台线程上运行,则应始终传入`TaskScheduler.Default`或使用`Task.Run`(如果可用). (3认同)