async和wait,同时将元素添加到List<;T>;

本文关键字:List gt lt 添加 元素 wait async | 更新日期: 2023-09-27 18:25:31

我编写了一个方法,它从许多来源向List添加元素。见下文:

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个元素。但是,我想知道如果这些方法同时返回元素,它是否会起作用。我应该锁定列表搜索项目吗?

谢谢你的建议。

async和wait,同时将元素添加到List<;T>;

您的项目没有同时运行,您启动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;
}