How to limit the amount of concurrent async I/O operations?

前端 未结 14 2503
遇见更好的自我
遇见更好的自我 2020-11-22 01:27
// let\'s say there is a list of 1000+ URLs
string[] urls = { \"http://google.com\", \"http://yahoo.com\", ... };

// now let\'s send HTTP requests to each of these          


        
14条回答
  •  情话喂你
    2020-11-22 02:13

    SemaphoreSlim can be very helpful here. Here's the extension method I've created.

        /// 
        /// Concurrently Executes async actions for each item of 
        /// 
        /// Type of IEnumerable
        /// instance of "/>
        /// an async  to execute
        /// Optional, max numbers of the actions to run in parallel,
        /// 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? maxActionsToRunInParallel = null)
        {
            if (maxActionsToRunInParallel.HasValue)
            {
                using (var semaphoreSlim = new SemaphoreSlim(
                    maxActionsToRunInParallel.Value, maxActionsToRunInParallel.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 of the provided 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);
    

提交回复
热议问题