做smtp.SendMailAsync(消息)在新线程中运行

本文关键字:线程 运行 新线程 smtp 消息 SendMailAsync | 更新日期: 2023-09-27 17:57:38

异步函数是否在新线程中运行。它继续正常执行。

smtp.SendMailAsync(message);     

如果Message列表中有100条消息:msgList,并且我们为此放置foreach,那么它将创建100个线程并并行运行。

foreach (var item in msgList)
{
    smtp.SendMailAsync(item);
}

请解释我,以及性能问题
请告诉我是否有更好的方法可以同时发送大量电子邮件。

做smtp.SendMailAsync(消息)在新线程中运行

首先,SendMailAsync不是TAP。你不能等待。其次,发送电子邮件时不需要线程,大部分"等待"时间都在服务器响应的延迟中。最后,"一次发送大量电子邮件是更好的方式吗?"?你发现了什么问题?

找出是否存在性能问题的最佳方法是尝试。

SendMailAsync和所有使用任务并行库的方法都在线程池线程中执行,但如果需要,可以让它们使用新线程。这意味着,不是创建新线程,而是从池中选择一个可用线程,并在方法完成时返回。

池中的线程数因.NET版本和操作系统、内核数等而异。在服务器操作系统上,它可以从.NET 4中的每个内核25个线程到.NET 4.5中的数百个或每个内核。

IO绑定(磁盘、网络)任务的另一个优化是使用IO完成端口,而不是使用线程。大致来说,这是IO操作(磁盘或网络)完成时来自IO堆栈的回调。这样,框架就不会浪费等待IO调用完成的线程。

启动异步网络操作时,.NET会进行网络调用、注册回调并释放线程池线程。当调用完成时,框架会收到通知,并在线程池线程上调度异步方法的其余部分(本质上是awaitContinueWith之后的部分)。

提交100个异步操作并不意味着将使用100个线程,也不意味着所有100个线程都将并行执行。相反,该框架将考虑内核的数量、负载和可用线程的数量,以便在不影响整体性能的情况下执行尽可能多的内核。等待网络调用可能根本不使用线程,而处理消息本身将在线程池线程

上执行

SendMailAsync只是SendAsync方法的TPL包装,但两种方法都不使用线程。相反,它使用一个称为IO完成端口(IOCP)的模型。

当您调用SendMailAsync时,您的线程会将邮件消息写入连接到SMTP服务器的套接字,并向操作系统注册回调,当客户端收到来自服务器的响应时,该回调将被执行。此回调由IO完成端口处理的"完成"事件触发。

回调本身是在线程池管理的多个IO完成线程之一上调用的。这个线程池只处理IO完成事件的回调。完成回调的一部分将调用SendMailAsync返回的Task标记为"已完成",允许任何等待的代码在自己的上下文中开始执行。