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(); });