Sunday, 29 July 2018

Call the Async method inside the Parallel.Foreach and wait for all Async methods to finish execution c#

In this post we are going to see how to call a Async methods inside Parallel.Foreach and wait for all Async methods to finish execution. First let we the Parallel.Foreach in c#


    public class Person
    {
        HttpHelper helper = new HttpHelper();

        public async Task CalculateParallel()
        {
            List<Product> products = new List<Product>();
            int successCount = 0;
            for (int i = 0; i < 50; i++)
            {
                products.Add(new Product());
            }

            Parallel.ForEach(products, async (prod) =>
            {
                await ParallelTask(prod);
                if (prod.Index > 0)
                    successCount++;
            });

            Console.WriteLine(successCount);           
        }

        public async Task ParallelTask(Product prod)
        {
            var data = await helper.Get("https://reqres.in/api/users/2");
            prod.Index = 1;
        }
    }

    public class Product
    {
        public int Index { get; set; }
    }


HttpHelper:

 public class HttpHelper
    {
        HttpClient client = new HttpClient();

        public async Task<string> Get(string url)
        {
            string dataObjects = string.Empty;
            // Add an Accept header for JSON format.
            client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

            // List data response.
            HttpResponseMessage response = await client.GetAsync(url);  /
            if (response.IsSuccessStatusCode)
            {
                // Parse the response body.
               dataObjects = await response.Content.ReadAsStringAsync();
            }
            else
            {
            Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            }
            return dataObjects;
        }
    }




In the above code you can see that we are populating a collection then in parallel.foreach we are iterating that collection and call the async method in parallel.foreach.

Now what will happen is the parallel.Foreach wont wait for all async method to finish, before that, it reaches the console.writeline , see the below screenshot the successCount is 0  instead of 50, that means it comes before finishing the all async methods to finish, you can see in the screenshot that index value assign after the console.writeline executes.





Now we will solve this issue , that is iterating the collection in parallel and will wait for all async methods to finish, To achieve this.

Solution
1. Open Manage Nuget Packages
2. Search for AsyncEnumerator version 2.2.1 and install it.



3. Add the following namespace in file using System.Collections.Async;
4. Now change your code like below

await products.ParallelForEachAsync(async (prod) =>
            {
                await ParallelTask(prod);
                if (prod.Index > 0)
                    successCount++;

            });

In the above code you can see that we are using await before {collections}.ParallelForeachAsync this will wait for all async methods to finish

public class Person
    {
        HttpHelper helper = new HttpHelper();

        public async Task CalculateParallel()
        {
            List<Product> products = new List<Product>();
            int successCount = 0;
            for (int i = 0; i < 50; i++)
            {
                products.Add(new Product());
            }

            await products.ParallelForEachAsync(async (prod) =>
            {
                await ParallelTask(prod);
                if (prod.Index > 0)
                    successCount++;
            });

            Console.WriteLine(successCount);           
        }

        public async Task ParallelTask(Product prod)
        {
            var data = await helper.Get("https://reqres.in/api/users/2");
            prod.Index = 1;
        }

    }

Now we can see the output like successCount is 50 in the below screenshot.




From the above code you can learn how to call the async methods inside the Parallel.Foreach and wait for all Async methods to finish execution.