Fow*_*owl 4 c# task-parallel-library async-await c#-5.0 .net-4.5
我有一个使用冷(未启动)任务的缓存类,以避免多次运行昂贵的东西.
public class AsyncConcurrentDictionary<TKey, TValue> : System.Collections.Concurrent.ConcurrentDictionary<TKey, Task<TValue>>
{
internal Task<TValue> GetOrAddAsync(TKey key, Task<TValue> 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;
}
}
Run Code Online (Sandbox Code Playgroud)
这很有效,直到您的任务实际使用C#5 await,ala实现
cache.GetOrAddAsync("key", new Task(async () => {
var r = await AsyncOperation();
return r.FastSynchronousTransform();
}));)`
Run Code Online (Sandbox Code Playgroud)
现在它看起来像TaskExtensions.Unwrap()我需要Task<Task<T>>变成一个Task<T>,但似乎它返回的包装实际上不支持Start()- 它抛出一个异常.
TaskCompletionSource (我去寻找稍微特殊的任务需求)似乎没有任何设施用于此类事情.
是否有替代方案TaskExtensions.Unwrap()支持"冷任务"?
你需要做的就是Task在打开它之前保持它并开始:
public Task<TValue> GetOrAddAsync(TKey key, Func<Task<TValue>> taskFunc)
{
Task<Task<TValue>> wrappedTask = new Task<Task<TValue>>(taskFunc);
Task<TValue> unwrappedTask = wrappedTask.Unwrap();
Task<TValue> cachedTask = base.GetOrAdd(key, unwrappedTask);
if (cachedTask == unwrappedTask)
wrappedTask.Start();
return cachedTask;
}
Run Code Online (Sandbox Code Playgroud)
用法:
cache.GetOrAddAsync(
"key", async () =>
{
var r = await AsyncOperation();
return r.FastSynchronousTransform();
});
Run Code Online (Sandbox Code Playgroud)