Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprenda Processing Collections Asynchronously | Async Loops and Processing Collections
C# Async and Await Practice

bookProcessing Collections Asynchronously

When you process large collections using asynchronous operations, it is tempting to launch an async task for every item at once. However, running too many concurrent operations can quickly overwhelm system resources such as CPU, memory, network bandwidth, or external services. This is especially true when interacting with databases, APIs, or file systems that have their own limits. To avoid exhausting resources or hitting external rate limits, you need to control how many operations run at a time. Two common strategies for this are batching and throttling.

Note
Definition

Batching means grouping items together and processing them in fixed-size chunks.
Throttling means limiting the number of concurrent operations, often using synchronization primitives like SemaphoreSlim, to avoid overwhelming resources.

Program.cs

Program.cs

copy
123456789101112131415161718192021222324252627282930313233343536373839
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace ConsoleApp { public class Program { public static async Task Main(string[] args) { List<int> numbers = Enumerable.Range(1, 20).ToList(); int batchSize = 5; Console.WriteLine("Starting batch processing..."); foreach (var batch in Batch(numbers, batchSize)) { var tasks = batch.Select(ProcessNumberAsync).ToList(); await Task.WhenAll(tasks); } Console.WriteLine("All batches complete."); } public static IEnumerable<List<T>> Batch<T>(List<T> items, int size) { for (int i = 0; i < items.Count; i += size) { yield return items.GetRange(i, Math.Min(size, items.Count - i)); } } public static async Task ProcessNumberAsync(int number) { Console.WriteLine($"Processing {number} on Task {Task.CurrentId}"); await Task.Delay(500); // Simulate async work } } }

This batching approach works by splitting the collection into smaller groups, or batches, and processing each batch in parallel. The Batch method divides the input list into sublists of the specified size. For each batch, you create a list of async tasks and use Task.WhenAll to await their completion before moving to the next batch. This limits the number of concurrent operations to the batch size, which helps control the degree of parallelism and prevents resource exhaustion.

To further control the number of concurrent async operations, especially when you do not want fixed-size batches, you can use a SemaphoreSlim. This allows you to throttle the number of operations running simultaneously, regardless of how many items are in your collection.

ThrottlingExample.cs

ThrottlingExample.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; // This is a non-runnable illustrative example. public class ThrottlingExample { public async Task ProcessWithThrottlingAsync(List<int> items, int maxConcurrency) { using (SemaphoreSlim semaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach (var item in items) { await semaphore.WaitAsync(); tasks.Add(Task.Run(async () => { try { await ProcessItemAsync(item); } finally { semaphore.Release(); } })); } await Task.WhenAll(tasks); } } private async Task ProcessItemAsync(int item) { // Simulate async work await Task.Delay(500); Console.WriteLine($"Processed {item}"); } }

Batching and throttling are essential techniques in many real-world scenarios. For instance, when calling a third-party API that enforces rate limits, batching your requests ensures you do not exceed the allowed number of concurrent calls. Throttling is similarly important when processing files, sending emails, or performing database operations, where too many simultaneous actions could degrade system performance or cause failures. By applying these strategies, you can build robust, scalable async applications that respect both system and external constraints.

1. Why might you want to batch async operations?

2. What is the purpose of using SemaphoreSlim in async code?

3. How does batching help with resource management?

question mark

Why might you want to batch async operations?

Select the correct answer

question mark

What is the purpose of using SemaphoreSlim in async code?

Select the correct answer

question mark

How does batching help with resource management?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 3

Pergunte à IA

expand

Pergunte à IA

ChatGPT

Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo

Suggested prompts:

Can you give an example of how to implement batching in code?

How does throttling with SemaphoreSlim work in practice?

What are some best practices for choosing batch sizes or throttle limits?

bookProcessing Collections Asynchronously

Deslize para mostrar o menu

When you process large collections using asynchronous operations, it is tempting to launch an async task for every item at once. However, running too many concurrent operations can quickly overwhelm system resources such as CPU, memory, network bandwidth, or external services. This is especially true when interacting with databases, APIs, or file systems that have their own limits. To avoid exhausting resources or hitting external rate limits, you need to control how many operations run at a time. Two common strategies for this are batching and throttling.

Note
Definition

Batching means grouping items together and processing them in fixed-size chunks.
Throttling means limiting the number of concurrent operations, often using synchronization primitives like SemaphoreSlim, to avoid overwhelming resources.

Program.cs

Program.cs

copy
123456789101112131415161718192021222324252627282930313233343536373839
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace ConsoleApp { public class Program { public static async Task Main(string[] args) { List<int> numbers = Enumerable.Range(1, 20).ToList(); int batchSize = 5; Console.WriteLine("Starting batch processing..."); foreach (var batch in Batch(numbers, batchSize)) { var tasks = batch.Select(ProcessNumberAsync).ToList(); await Task.WhenAll(tasks); } Console.WriteLine("All batches complete."); } public static IEnumerable<List<T>> Batch<T>(List<T> items, int size) { for (int i = 0; i < items.Count; i += size) { yield return items.GetRange(i, Math.Min(size, items.Count - i)); } } public static async Task ProcessNumberAsync(int number) { Console.WriteLine($"Processing {number} on Task {Task.CurrentId}"); await Task.Delay(500); // Simulate async work } } }

This batching approach works by splitting the collection into smaller groups, or batches, and processing each batch in parallel. The Batch method divides the input list into sublists of the specified size. For each batch, you create a list of async tasks and use Task.WhenAll to await their completion before moving to the next batch. This limits the number of concurrent operations to the batch size, which helps control the degree of parallelism and prevents resource exhaustion.

To further control the number of concurrent async operations, especially when you do not want fixed-size batches, you can use a SemaphoreSlim. This allows you to throttle the number of operations running simultaneously, regardless of how many items are in your collection.

ThrottlingExample.cs

ThrottlingExample.cs

copy
1234567891011121314151617181920212223242526272829303132333435363738394041
using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; // This is a non-runnable illustrative example. public class ThrottlingExample { public async Task ProcessWithThrottlingAsync(List<int> items, int maxConcurrency) { using (SemaphoreSlim semaphore = new SemaphoreSlim(maxConcurrency)) { List<Task> tasks = new List<Task>(); foreach (var item in items) { await semaphore.WaitAsync(); tasks.Add(Task.Run(async () => { try { await ProcessItemAsync(item); } finally { semaphore.Release(); } })); } await Task.WhenAll(tasks); } } private async Task ProcessItemAsync(int item) { // Simulate async work await Task.Delay(500); Console.WriteLine($"Processed {item}"); } }

Batching and throttling are essential techniques in many real-world scenarios. For instance, when calling a third-party API that enforces rate limits, batching your requests ensures you do not exceed the allowed number of concurrent calls. Throttling is similarly important when processing files, sending emails, or performing database operations, where too many simultaneous actions could degrade system performance or cause failures. By applying these strategies, you can build robust, scalable async applications that respect both system and external constraints.

1. Why might you want to batch async operations?

2. What is the purpose of using SemaphoreSlim in async code?

3. How does batching help with resource management?

question mark

Why might you want to batch async operations?

Select the correct answer

question mark

What is the purpose of using SemaphoreSlim in async code?

Select the correct answer

question mark

How does batching help with resource management?

Select the correct answer

Tudo estava claro?

Como podemos melhorá-lo?

Obrigado pelo seu feedback!

Seção 2. Capítulo 3
some-alt