Cold Tasks和TaskExtensions.Unwrap

我有一个缓存类,它使用冷(未启动)任务来避免多次运行昂贵的东西。

public class AsyncConcurrentDictionary : System.Collections.Concurrent.ConcurrentDictionary<TKey, Task> { internal Task GetOrAddAsync(TKey key, Task newTask) { var cachedTask = base.GetOrAdd(key, newTask); if (cachedTask == newTask && cachedTask.Status == TaskStatus.Created) // We won! our task is now the cached task, so run it cachedTask.Start(); return cachedTask; } } 

这很有效,直到你的任务实际使用C#5的await ,ala实现

 cache.GetOrAddAsync("key", new Task(async () => { var r = await AsyncOperation(); return r.FastSynchronousTransform(); }));)` 

现在,看起来TaskExtensions.Unwrap()通过将Task<Task>转换为Task我所需要的,但似乎它返回的包装器实际上不支持Start() – 它会抛出exception。

TaskCompletionSource (我需要稍微特殊的任务需求)似乎没有任何设施可用于此类事情。

是否有替代TaskExtensions.Unwrap()支持“冷任务”?

您需要做的就是在打开Task之前保留Task并开始:

 public Task GetOrAddAsync(TKey key, Func> taskFunc) { Task> wrappedTask = new Task>(taskFunc); Task unwrappedTask = wrappedTask.Unwrap(); Task cachedTask = base.GetOrAdd(key, unwrappedTask); if (cachedTask == unwrappedTask) wrappedTask.Start(); return cachedTask; } 

用法:

 cache.GetOrAddAsync( "key", async () => { var r = await AsyncOperation(); return r.FastSynchronousTransform(); });