同步函数内的异步调用

我正在尝试异步填充我的缓存

static ConcurrentDictionary data = new ConcurrentDictionary(); public static async Task GetStuffAsync(string key) { return data.GetOrAdd(key, async (x) => { return await LoadAsync(x); }); } static async Task LoadAsync(string key) {....} 

但这给了我错误:

无法将异步lambda表达式转换为委托类型’System.Func’。

异步lambda表达式可能返回void,Task或Task,其中任何一个都不能转换为’System.Func’。

据我所知,这是因为GetOrAdd()不是异步的。 我该如何解决这个问题?

更新: LazyAsync建议的LazyAsync将在我的简单示例中起作用。 或者,像这样的解决方法(肯定可以忍受它引入的一些开销):

 public static async Task GetStuffAsync(string key) { string[] d = null; if (!data.ContainsKey(key)) d = await LoadAsync(key); return data.GetOrAdd(key, d); } 

那么问题就变成微软没有时间更新所有接口以支持异步,或者我正在尝试做一些非常错误的事情(并且ConcurrentDictionary不应该有GetOrAddAsync() )?

异步方法(或lambda)只能返回voidTaskTask但是你的lambda会返回string[] ,因此编译器会阻止你。

await关键字已经过优化,可以在任务完成后同步继续。 因此,一种选择是将Task本身存储在字典中,而不必担心一次又一次地等待已完成的Task。

 private static ConcurrentDictionary> data = new ConcurrentDictionary>(); public static Task GetStuffAsync(string key) { return data.GetOrAdd(key, LoadAsync); } 

而当你这样做

 var item = await GetStuffAsync(...); 

第一次它将(a)等待缓存的任务完成 – 之后它将继续同步。

您必须考虑LoadAsync失败时应该发生什么。 因为我们正在缓存LoadAsync返回的LoadAsync ; 如果失败了,我们将愚蠢地缓存失败的任务。 您可能需要处理此问题。