同步功能内的异步调用 [英] Async call within synchronous function

查看:88
本文介绍了同步功能内的异步调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试异步填充缓存

I'm trying to populate my cache asynchronously

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'。

Cannot convert async lambda expression to delegate type 'System.Func'.

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

An async lambda expression may return void, Task or Task, none of which are convertible to 'System.Func'.

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

As I understand this is because GetOrAdd() is not asynchronous. How can I fix the issue?

更新:建议使用
LazyAsync 在评论中将适用于我的琐碎示例。或者,这样的解决方法(肯定会带来一些开销):

Update: LazyAsync suggested in the comments will work in my trivial example. Or, workaround like this (can definitely live with some overhead it introduces):

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())?

The question then becomes did Microsoft just have no time to update all interfaces to support async or I'm trying to do something deeply wrong (and ConcurrentDictionary shouldn't have GetOrAddAsync()) ?

推荐答案

异步方法(或lambda)只能返回 void Task Task< T> ,但是您的lambda返回 string []

Async methods (or lambda) can only return void or Task or Task<T> but your lambda returns string[] and thus compiler prevents you.

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

await keyword is optimized to continue synchronously when the Task is already completed. So, one option is to store the Task itself in dictionary and don't worry about awaiting the completed Task again and again.

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完成-之后将继续同步。

first time it will (a)wait till the cached Task finishes --There after it will continue synchronously.

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

You'll have to think about what should happen when LoadAsync fails. Because we're caching the Task returned by LoadAsync; if that fails we'll foolishly cache the failed Task. You may need to handle this.

这篇关于同步功能内的异步调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆