【发布时间】:2015-03-19 22:44:53
【问题描述】:
我正在尝试异步填充我的缓存
static ConcurrentDictionary<string, string[]> data = new ConcurrentDictionary<string, string[]>();
public static async Task<string[]> GetStuffAsync(string key)
{
return data.GetOrAdd(key, async (x) => {
return await LoadAsync(x);
});
}
static async Task<string[]> LoadAsync(string key) {....}
但这给了我错误:
无法将异步 lambda 表达式转换为委托类型“System.Func”。
异步 lambda 表达式可能返回 void、Task 或 Task,它们都不能转换为 'System.Func'。
据我了解,这是因为 GetOrAdd() 不是异步的。我该如何解决这个问题?
更新:
cmets 中建议的LazyAsync 将适用于我的简单示例。或者,像这样的解决方法(肯定可以忍受它引入的一些开销):
public static async Task<string[]> GetStuffAsync(string key)
{
string[] d = null;
if (!data.ContainsKey(key))
d = await LoadAsync(key);
return data.GetOrAdd(key, d);
}
那么问题就变成了微软只是没有时间更新所有接口以支持异步还是我试图做一些严重错误的事情(ConcurrentDictionary 不应该有GetOrAddAsync())?
【问题讨论】:
-
不是答案,但可能对你来说很有趣:你见过AsyncLazy吗?
-
嗯,你不能用你有的界面来做。
await仅在跨异步层时才有效,而您缺少一个 - 方法GetOrAdd本身。您需要一个本身是异步的版本,并等待整个GetOrAdd方法(注意您现在实际上没有这样做 - 这是另一个问题)。可悲的是,这意味着要编写自己的 ConcurrentDictionary,这会造成伤害。 -
为什么
ConcurrentDictionary应该有GetOrAddAsync?它是内存中的同步收集。它没有理由有这样的方法。 -
@Sriram Sakthivel,那我肯定做错了,我想了解究竟是什么(可能我需要使用其他缓存模式或其他东西)。 async/await 的全部目标是简单的异步代码,对吧?尽管您的解决方案非常聪明,但我无法证明它的复杂性。
-
@UserControl 您的假设是正确的。 async/await 的全部目标是简单的异步代码,它适用于异步方法 (API),但不适用于非异步 API。您正在尝试异步访问同步 API;这实际上没有任何意义。好的,如果您不相信我的回答,您可以在
GetStuffAsyncversion2 上做一些工作以使其线程安全,这应该没问题。
标签: c# .net asynchronous async-await