async and await while adding elements to List

2019-07-15 12:46发布

I wrote method, which adds elements to the List from many sources. See below:

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;
    }

I tested this method and works propertly. I suppose that it works propertly, because GetPlaces method return 160 elements and GetGroups return 3000. But, I was wondering if it will work if the methods return elements in the same time. Should I lock list searchingItems ?

Thank you for advice.

1条回答
男人必须洒脱
2楼-- · 2019-07-15 12:51

Your items do not run at the same time, you start GetPlaces(), stop and wait for GetPlaces() result, then go in to the first loop. You then start GetGroups(), stop and wait for GetGroups() result, then go in to the second loop. Your loops are not concurrent so you have no need to lock while adding them.

However if you have noticed your two async methods are also not concurrent, you can easily modify your program to make it so though.

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;
}

What this will do will start GetPlaces(), start GetGroups(), stop and wait for GetPlaces() result, then go in to the first loop, stop and wait for GetGroups() result, then go in to the second loop.

The two loops are still not concurrent, but your two await-able methods are which may give you a small performance boost. I doubt you would get any benifit from making the loops concurrent, they appear to just be building models and the overhead of making it thread safe would not be worth it for how little work is being done.

If you really wanted to try and make it more parallel (but I doubt you will see much benefit) is use PLINQ to build your models.

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;
}
查看更多
登录 后发表回答