同步函数内的异步调用
Async call within synchronous function
我正在尝试异步填充缓存
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) {....}
但这给了我错误:
Cannot convert async lambda expression to delegate type 'System.Func'.
An async lambda expression may return void, Task or Task, none of which are convertible to 'System.Func'.
据我了解,这是因为 GetOrAdd()
不是异步的。我该如何解决这个问题?
更新:
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()
)?
异步方法(或 lambda)只能 return void
或 Task
或 Task<T>
但您的 lambda returns string[]
和因此编译器会阻止你。
await
关键字优化为在任务已完成时同步继续。因此,一种选择是将任务本身存储在字典中,而不必担心一次又一次地等待完成的任务。
private static ConcurrentDictionary<string, Task<string[]>> data =
new ConcurrentDictionary<string, Task<string[]>>();
public static Task<string[]> GetStuffAsync(string key)
{
return data.GetOrAdd(key, LoadAsync);
}
当你这样做时
var item = await GetStuffAsync(...);
第一次它将 (a) 等到缓存的任务完成 -- 之后它将同步继续。
您将不得不考虑当 LoadAsync
失败时应该发生什么。因为我们正在缓存由 LoadAsync
编辑的 return 任务;如果失败,我们将愚蠢地缓存失败的任务。您可能需要处理这个问题。
我正在尝试异步填充缓存
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) {....}
但这给了我错误:
Cannot convert async lambda expression to delegate type 'System.Func'.
An async lambda expression may return void, Task or Task, none of which are convertible to 'System.Func'.
据我了解,这是因为 GetOrAdd()
不是异步的。我该如何解决这个问题?
更新:
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()
)?
异步方法(或 lambda)只能 return void
或 Task
或 Task<T>
但您的 lambda returns string[]
和因此编译器会阻止你。
await
关键字优化为在任务已完成时同步继续。因此,一种选择是将任务本身存储在字典中,而不必担心一次又一次地等待完成的任务。
private static ConcurrentDictionary<string, Task<string[]>> data =
new ConcurrentDictionary<string, Task<string[]>>();
public static Task<string[]> GetStuffAsync(string key)
{
return data.GetOrAdd(key, LoadAsync);
}
当你这样做时
var item = await GetStuffAsync(...);
第一次它将 (a) 等到缓存的任务完成 -- 之后它将同步继续。
您将不得不考虑当 LoadAsync
失败时应该发生什么。因为我们正在缓存由 LoadAsync
编辑的 return 任务;如果失败,我们将愚蠢地缓存失败的任务。您可能需要处理这个问题。