Nesting await in Parallel.ForEach

后端 未结 9 1677
别跟我提以往
别跟我提以往 2020-11-22 01:01

In a metro app, I need to execute a number of WCF calls. There are a significant number of calls to be made, so I need to do them in a parallel loop. The problem is that th

9条回答
  •  小鲜肉
    小鲜肉 (楼主)
    2020-11-22 01:28

    An extension method for this which makes use of SemaphoreSlim and also allows to set maximum degree of parallelism

        /// 
        /// Concurrently Executes async actions for each item of 
        /// 
        /// Type of IEnumerable
        /// instance of "/>
        /// an async  to execute
        /// Optional, An integer that represents the maximum degree of parallelism,
        /// Must be grater than 0
        /// A Task representing an async operation
        /// If the maxActionsToRunInParallel is less than 1
        public static async Task ForEachAsyncConcurrent(
            this IEnumerable enumerable,
            Func action,
            int? maxDegreeOfParallelism = null)
        {
            if (maxDegreeOfParallelism.HasValue)
            {
                using (var semaphoreSlim = new SemaphoreSlim(
                    maxDegreeOfParallelism.Value, maxDegreeOfParallelism.Value))
                {
                    var tasksWithThrottler = new List();
    
                    foreach (var item in enumerable)
                    {
                        // Increment the number of currently running tasks and wait if they are more than limit.
                        await semaphoreSlim.WaitAsync();
    
                        tasksWithThrottler.Add(Task.Run(async () =>
                        {
                            await action(item).ContinueWith(res =>
                            {
                                // action is completed, so decrement the number of currently running tasks
                                semaphoreSlim.Release();
                            });
                        }));
                    }
    
                    // Wait for all tasks to complete.
                    await Task.WhenAll(tasksWithThrottler.ToArray());
                }
            }
            else
            {
                await Task.WhenAll(enumerable.Select(item => action(item)));
            }
        }
    

    Sample Usage:

    await enumerable.ForEachAsyncConcurrent(
        async item =>
        {
            await SomeAsyncMethod(item);
        },
        5);
    

提交回复
热议问题