【问题标题】:async and await while adding elements to List<T>向 List<T> 添加元素时异步和等待
【发布时间】:2014-11-29 15:19:21
【问题描述】:

我编写了方法,该方法将来自许多来源的元素添加到列表中。见下文:

public static async Task<List<SearchingItem>> GetItemsToSelect()
    {
        List<SearchingItem> searchingItems = new List<SearchingItem>();

        foreach (Place place in await GetPlaces())
        {
            searchingItems.Add(new SearchingItem() { 
                IdFromRealModel=place.Id, NameToDisplay=place.FullName, 
                ExtraInformation=place.Name, TypeOfSearchingItem=TypeOfSearchingItem.PLACE });
        }

        foreach (Group group in await GetGroups())
        {
            searchingItems.Add(new SearchingItem()
            {
                IdFromRealModel = group.Id, NameToDisplay = group.Name,
                ExtraInformation = group.TypeName, TypeOfSearchingItem = TypeOfSearchingItem.GROUP
            });
        }

        return searchingItems;
    }

我测试了这个方法并且工作正常。我想它可以正常工作,因为 GetPlaces 方法返回 160 个元素,而 GetGroups 返回 3000。但是,我想知道如果这些方法同时返回元素,它是否会起作用.我应该锁定列表 searchingItems 吗?

感谢您的建议。

【问题讨论】:

  • Should I lock list searchingItems, 否,因为在第一个循环完成之前不会执行第二个循环。

标签: c# asynchronous multitasking async-await


【解决方案1】:

您的项目没有同时运行,您启动GetPlaces(),停止并等待GetPlaces() 结果,然后进入第一个循环。然后启动GetGroups(),停止并等待GetGroups() 结果,然后进入第二个循环。您的循环不是并发的,因此您在添加它们时无需锁定。

但是,如果您注意到您的两个异步方法也不是并发的,您可以轻松地修改您的程序以使其如此。

public static async Task<List<SearchingItem>> GetItemsToSelect()
{
    List<SearchingItem> searchingItems = new List<SearchingItem>();
    var getPlacesTask = GetPlaces();
    var getGroupsTask = GetGroups();

    foreach (Place place in await getPlacesTask)
    {
        searchingItems.Add(new SearchingItem() { 
            IdFromRealModel=place.Id, NameToDisplay=place.FullName, 
            ExtraInformation=place.Name, TypeOfSearchingItem=TypeOfSearchingItem.PLACE });
    }

    foreach (Group group in await getGroupsTask)
    {
        searchingItems.Add(new SearchingItem()
        {
            IdFromRealModel = group.Id, NameToDisplay = group.Name,
            ExtraInformation = group.TypeName, TypeOfSearchingItem = TypeOfSearchingItem.GROUP
        });
    }

    return searchingItems;
}

这会做什么将启动GetPlaces(),启动GetGroups(),停止并等待GetPlaces()结果,然后进入第一个循环,停止并等待GetGroups()结果,然后进入第二个循环循环。

这两个循环仍然不是并发的,但是您的两个可等待方法可能会给您带来小的性能提升。我怀疑您是否会从使循环并发中获得任何好处,它们似乎只是在构建模型,并且由于所做的工作很少,使其线程安全的开销不值得。

如果您真的想尝试使其更加并行(但我怀疑您会看到很多好处),请使用 PLINQ 来构建您的模型。

public static async Task<List<SearchingItem>> GetItemsToSelect()
{
    var getPlacesTask = GetPlaces();
    var getGroupsTask = GetGroups();

    var places = await getPlacesTask;

    //Just make the initial list from the LINQ object.
    List<SearchingItem> searchingItems = places.AsParallel().Select(place=>
        new SearchingItem() { 
            IdFromRealModel=place.Id, NameToDisplay=place.FullName, 
            ExtraInformation=place.Name, TypeOfSearchingItem=TypeOfSearchingItem.PLACE 
        }).ToList();

    var groups = await getGroupsTask;

    //build up a PLINQ IEnumerable
    var groupSearchItems = groups.AsParallel().Select(group=>
        new SearchingItem()
        {
            IdFromRealModel = group.Id, NameToDisplay = group.Name,
            ExtraInformation = group.TypeName, TypeOfSearchingItem = TypeOfSearchingItem.GROUP
        });

    //The building of the IEnumerable was parallel but the adding is serial.
    searchingItems.AddRange(groupSearchItems);

    return searchingItems;
}

【讨论】:

    猜你喜欢
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 2020-01-02
    相关资源
    最近更新 更多