在向List <T>添加元素时进行异步和等待

pio*_*lut 4 c# asynchronous multitasking async-await

我编写了方法,它从许多来源向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;
    }
Run Code Online (Sandbox Code Playgroud)

我测试了这种方法,并且有效地工作.我想,它的工作原理propertly,因为GetPlaces方法返回160元和GetGroups返回3000但是,我在想,如果,如果方法返回的同时元素会工作.我应该锁定列表searchItems吗?

谢谢你的建议.

Sco*_*ain 5

您的物品不会同时运行,您启动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;
}
Run Code Online (Sandbox Code Playgroud)

这将做什么将启动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;
}
Run Code Online (Sandbox Code Playgroud)