Parallelization processes independent work items simultaneously so an operation can finish sooner. A mail merge exposes the problem: sending messages sequentially can exceed a web request’s timeout, while concurrent sends wait mainly on the slowest message. section 8.0 section 8.1
Choose the execution mechanism according to workload and resource limits:
- Use Thread for direct control, but bound concurrency because one thread per item can create thousands of threads and degrade server performance. section 8.1.1
- Use the thread pool through ThreadPool.QueueUserWorkItem or Task.Run for efficient, self-tuning scheduling; expect slower ramp-up when submitting a large burst. section 8.3
- Prefer asynchronous operations for I/O-bound work that mostly waits, because blocked worker threads otherwise overwhelm the thread pool. section 8.1.3
- Use Parallel for simpler thread-pool syntax, but measure and configure MaxDegreeOfParallelism for large collections. section 8.3
Mail merge and thread overhead
A thread-per-message mail merge starts one thread for every recipient and waits for all threads. A benchmark creating 1,000 sleeping threads completes in roughly 1.1–1.2 seconds outside the debugger, while 100,000 threads take 15–20 seconds. An asynchronous version replaces Send with SendMailAsync and Task.Delay for waiting work, measuring about 1,001–1,017 milliseconds for 1,000 tasks. section 8.1.1 section 8.1.3
Listing 8.6 Asynchronous mail merge using Task.Run
void MailMerge(
string from,
string subject,
string text,
(string email,string name)[] recipients)
{
var processingTasks = new Task[recipients.Length];
for(int i=0;i< recipients.Length;++i)
{
processingTasks[i] = Task.Run(async ()=> #1
{
try
{
var sender = new SmtpClient("smtp.example.com");
var message = new MailMessage();
message.From = new MailAddress(from);
message.Subject = subject;
message.To.Add(new MailAddress(recipients[i].email));
message.Body = text.Replace("{name}", recipients[i].name);
await sender.SendMailAsync(message); #2
}
catch
{
LogFailure(current.email);
}
});
}
Task.WaitAll(processingTasks);
}
#1 Added async
#2 Added await
Inspect the asynchronous mail-merge listing showing Task.Run, SendMailAsync, per-recipient tasks, and exception logging. section 8.1.3





































