由于发送电子邮件是一个 I/O 绑定过程,因此生成线程来发送电子邮件不会实现太多(如果有的话)加速。
如果您使用的是属于 Windows 的 SMTP 服务器,那么当您“发送”一封电子邮件时,它实际上并没有在那个时刻被发送。它位于服务器上的队列中,服务器尽可能快地发送它们。发送电子邮件实际上是一个缓慢的过程。
我想我要说的是有两种选择:
- 只需按顺序发送它们,看看是否满足您的性能要求。
- 您可以使用称为“数据并行”的并行编程概念,我在博客文章Data Parallel – Parallel Programming in C#/.NET
基本上,您所做的是,您将获得所有数据(一口气)。原因是批量获取数据也会减慢您的流程,因此如果您对性能感兴趣(这就是我猜您尝试使用线程的原因),那么不要对数据库服务器进行多次往返(这也是两个级别的 I/O 绑定,网络 I/O 和磁盘 I/O)。
因此,获取您的数据,并将其拆分为块或分区。这一切都在我指出的文章中进行了解释。天真的实现是块的数量等于机器上的核心数量。
每个块由一个线程处理。当所有线程都完成后,你就完成了。借助 .NET 4.0 中 ThreadPool 的新功能(如果您使用 Parallel.For 或 PLINQ 或 Tasks),您将获得一些其他好处,例如“工作窃取”以进一步加快工作速度。
我认为 Parallel.For/Parallel.ForEach 对你很有效。
编辑
刚刚注意到 .NET 3.5 的要求。好吧,这些概念仍然适用,但您没有 Parallel.For/ForEach。所以这是一个使用 ThreadPool 并使用数据并行技术的实现(根据我的博客文章修改)。
private static void SendEmailsUsingThreadPool(List<Recipient> recipients)
{
var coreCount = Environment.ProcessorCount;
var itemCount = recipients.Count;
var batchSize = itemCount / coreCount;
var pending = coreCount;
using (var mre = new ManualResetEvent(false))
{
for (int batchCount = 0; batchCount < coreCount; batchCount++)
{
var lower = batchCount * batchSize;
var upper = (batchCount == coreCount - 1) ? itemCount : lower + batchSize;
ThreadPool.QueueUserWorkItem(st =>
{
for (int i = lower; i < upper; i++)
SendEmail(recipients[i]);
if (Interlocked.Decrement(ref pending) == 0)
mre.Set();
});
}
mre.WaitOne();
}
}
private static void SendEmail(Recipient recipient)
{
//Send your Emails here
}
}
class Recipient
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
}
因此,获取您的数据并调用 SendEmailUsingThreadPool() 将您的数据传递给它。当然不要这样称呼你的方法:)。如果您有 DataSet/DataTable,则只需修改实现以接受 DataSet/DataTable。这种方法负责将您的数据分成块,因此您不必担心任何这些。简单地调用它。