【问题标题】:Cold Tasks and TaskExtensions.Unwrap冷任务和 TaskExtensions.Unwrap
【发布时间】:2013-08-14 14:32:48
【问题描述】:

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

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

在您的任务实际使用 C#5 的 await 实现之前,这非常有效,ala

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

现在看起来TaskExtensions.Unwrap() 完全符合我的需要,将Task&lt;Task&lt;T&gt;&gt; 转换为Task&lt;T&gt;,但它返回的包装器似乎实际上并不支持Start() - 它会引发异常。

有没有支持“冷任务”的TaskExtensions.Unwrap() 的替代品?

【问题讨论】:

  • 你为什么不重新表述你的问题?我已多次阅读,但仍然无法理解您想要实现的目标。也许其他人也是如此,这就是为什么您还没有得到任何答案的原因
  • 哪部分不明白? Task.Unwrap 返回一个已经启动的“Promise 风格”任务,而我需要未启动 Task 实例,以便我可以将它们合并到我的缓存中。

标签: c# task-parallel-library .net-4.5 async-await c#-5.0


【解决方案1】:

您需要做的就是在打开 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;
}

用法:

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

【讨论】:

    猜你喜欢
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 2021-06-28
    相关资源
    最近更新 更多