【问题标题】:Is this a good candidate for using async await in this C# .NET code?这是在这个 C# .NET 代码中使用异步等待的好选择吗?
【发布时间】:2013-07-16 20:09:14
【问题描述】:

我有一个对象集合。在保存这些对象之前,我需要从数据库中获取一些参考数据。我需要为每个对象对数据库进行几次调用。这些方法可以按任何顺序发生/不相互依赖。

我可以使用async / await 使这些数据库操作同时发生 吗?

Parallel.ForEach(animals,
    animal => {
        animal.Owner = GetAnimalOwner(ownerId);
        animal.FavouriteFood = GetFavouriteFood(foodId);

        Database.Store(animal);
    });

这是一些伪代码,解释了我正在尝试做的事情。 这是async / await 的好人选吗?

【问题讨论】:

    标签: c# .net asynchronous parallel-processing async-await


    【解决方案1】:

    如果你只想并行执行这两个操作,那么你不需要async-await。您可以使用旧的 TPL 方法,例如 Parallel.Invoke():

    Parallel.ForEach(animals,
        animal => {
            Parallel.Invoke(
                () => animal.Owner = GetAnimalOwner(ownerId),
                () => animal.FavouriteFood = GetFavouriteFood(foodId));
    
            Database.Store(animal);
        });
    

    请记住,不能保证这会真正提高您的性能,具体取决于您的数据库和您与它的连接。

    一般来说,async-await 在两种情况下是有意义的:

    1. 您想从 UI 线程中卸载一些长时间运行的代码。
    2. 您希望使用更少的线程来提高性能或可扩展性。

    在我看来,#1 不是你的情况。如果您是第 2 种情况,那么您应该将数据库方法重写为真正异步的方法(取决于您的数据库库,这可能是不可能的)。

    如果你这样做,那么你可以做类似于 Scott Chamberlain 建议的事情(但使用Parallel.ForEach()):

    var tasks = animals.Select(
        async animal => {
            var getOwnerTask = GetAnimalOwnerAsync(ownerId);
            var getFavouriteFoodTask = GetFavouriteFoodAsync(foodId);
    
            animal.Owner = await getOwnerTask;
            animal.FavouriteFood = await getFavouriteFoodTask;
    
            await Database.StoreAsync(animal);
        });
    
    await Task.WhenAll(tasks);
    

    这将以比Parallel.ForEach() 更大的并行度执行(因为受线程池的限制),但同样,这实际上可能不会提高性能。如果你想限制并行度,你可以添加SemaphoreSlim或者你可以使用TPL Dataflow来代替。

    【讨论】:

    • @downvoter 你想分享你认为这个答案有什么问题吗?
    • 在您的第二个代码块中,GetAnimalOwnerAsyncGetFavouriteFoodAsync 会在调用 StoreAsync 之前 100% 完成吗?
    • @Pure.Krome 是的,这两个awaits 确保了这一点。
    • 啊! kewl :) 还有 2 个 Q。 a) 为什么不直接执行await GetAnimalOwnerAsync(ownerId) 而不是获取变量然后等待该变量? (对于GetAnimalOwnerAsyncGetFavouriteFoodAsync)? b) 你能提供一些GetFavouriteFoodAsync 的示例代码吗.. 当然里面的逻辑可以是注释=> // do logic here ..
    • @Pure.Krome a) 因为只有在 GetAnimalOwnerAsync() 完成后才会启动 GetFavouriteFoodAsync()。我认为这不是你想要的。 b) 它看起来与同步版本非常相似,除了您将每个 CallDbMethod() 替换为 await CallDbMethodAsync() (再次假设您的数据库库支持异步)。
    猜你喜欢
    • 2013-10-17
    • 2022-01-23
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多