使用SendEmailAsync与Parallel.ForEach遇问题,咨询其并行可用性
SendEmailAsync能否用于并行方法?
SendEmailAsync本身完全支持异步并行执行,但你当前的用法存在问题,这才导致控制台程序无响应。
问题根源
Parallel.ForEach是为CPU密集型的同步任务设计的,它不兼容异步委托。你传入的async item => ...会被当作async void方法处理:
async void的异常无法被常规方式捕获,可能导致程序悄悄崩溃;- Parallel.ForEach不会等待异步操作完成,主线程会直接继续执行,控制台程序的主线程如果没等待所有异步发邮件任务结束,就会直接退出,表现为“停止运行且无响应”。
正确的异步并行写法
处理发邮件这类I/O密集型异步任务,应该用Task.WhenAll结合异步遍历:
// 遍历所有记录,创建异步任务 var emailTasks = registros.Select(async item => { // ... 这里写你的前置逻辑,比如构造myMessage var response = await client.SendEmailAsync(myMessage).ConfigureAwait(false); }); // 等待所有异步邮件任务完成 await Task.WhenAll(emailTasks);
额外注意事项
- 邮件服务商通常有并发发送限制,并行数量过多可能被限流、封禁IP,建议根据服务商规则控制并发数。
- 如需手动控制并发量,可以用
SemaphoreSlim实现限流:
// 限制同时最多5个并发任务 var semaphore = new SemaphoreSlim(5); var emailTasks = registros.Select(async item => { await semaphore.WaitAsync().ConfigureAwait(false); try { // ... 构造邮件、发送逻辑 var response = await client.SendEmailAsync(myMessage).ConfigureAwait(false); } finally { // 释放信号量,允许下一个任务执行 semaphore.Release(); } }); await Task.WhenAll(emailTasks);
内容的提问来源于stack exchange,提问作者David Programer
相关产品推荐
相关产品推荐

