繁体   English   中英

同步功能内的异步调用

[英]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) {....}

但这给了我错误:

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

异步lambda表达式可能返回void,Task或Task,这些都不可转换为'System.Func'。

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

更新: LazyAsync建议的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);
}

然后,问题就变成了Microsoft是否没有时间更新所有接口来支持异步,或者我正尝试做一些严重错误的事情(并且ConcurrentDictionary不应该具有GetOrAddAsync() )?

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

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

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)等到缓存的Task完成-之后将同步继续。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM