Esempio n. 1
0
        /// <summary>
        /// Asynchronously runs <paramref name="delegateFunction"/> for every item in the given collection
        /// </summary>
        /// <typeparam name="T">Type of the collection item</typeparam>
        /// <param name="delegateFunction">The function to asynchronously run</param>
        /// <param name="collection">The collection to be enumerated</param>
        /// <exception cref="InvalidOperationException">Thrown if execution starts before the end of another operation</exception>
        public async Task RunForEach <T>(IEnumerable <T> collection, ForEachItemAsync <T> delegateFunction)
        {
            if (RunningTasks.Count > 0)
            {
                throw new InvalidOperationException(Properties.Resources.AsyncFor_ErrorNoConcurrentExecution);
            }

            var exceptions    = new List <Exception>();
            var taskItemQueue = new Queue <T>();

            foreach (var item in collection)
            {
                taskItemQueue.Enqueue(item);
            }

            TotalTasks = taskItemQueue.Count;

            // While there's either more tasks to start or while there's still tasks running
            while (taskItemQueue.Count > 0 || (taskItemQueue.Count == 0 && RunningTasks.Count > 0))
            {
                if ((BatchSize < 1 || RunningTasks.Count < BatchSize) && taskItemQueue.Count > 0)
                {
                    // We can run more tasks

                    // Get the next task item to run
                    var item = taskItemQueue.Dequeue(); // The item in Collection to process

                    // Start the task
                    var tTask = Task.Run(async() =>
                    {
                        await delegateFunction(item).ConfigureAwait(false);
                        IncrementCompletedTasks();
                    });

                    // Either wait for it or move on
                    if (RunSynchronously)
                    {
                        await tTask.ConfigureAwait(false);
                    }
                    else
                    {
                        RunningTasks.Add(tTask);
                    }
                }
                else
                {
                    if (RunningTasks.Count > 0)
                    {
                        // We can't start any more tasks, so we have to wait on one.
                        await Task.WhenAny(RunningTasks).ConfigureAwait(false);

                        // Remove completed tasks
                        for (var count = RunningTasks.Count - 1; count >= 0; count--)
                        {
                            if (RunningTasks[count].Exception != null)
                            {
                                var ex = RunningTasks[count].Exception;
                                if (ex is AggregateException aggregateEx && aggregateEx.InnerExceptions.Count == 1)
                                {
                                    exceptions.Add(aggregateEx.InnerExceptions.First());
                                }
                                else
                                {
                                    exceptions.Add(RunningTasks[count].Exception);
                                }

                                RunningTasks.RemoveAt(count);
                            }
                            else if (RunningTasks[count].IsCompleted)
                            {
                                RunningTasks.RemoveAt(count);
                            }
                        }
                    }