由于发送电子邮件是一个 I/O 绑定过程,因此生成线程来发送电子邮件不会实现太多(如果有的话)加速。
如果您使用的是 Windows 一部分的 SMTP 服务器,那么当您“发送”电子邮件时,它实际上并不会立即发送。它位于服务器上的队列中,服务器会尽快发送它们。发送电子邮件实际上是一个缓慢的过程。
我想我想说的是有两种选择:
- 只需按顺序发送它们,看看是否满足您的性能要求。
- 您可以使用称为“数据并行”的并行编程概念,我已在博客文章中举例说明了它数据并行 – C#/.NET 中的并行编程
基本上,您所做的是,您将获得所有数据(一次性)。原因是批量获取数据也会减慢您的进程,因此如果您对性能感兴趣(这就是我猜测您正在尝试使用线程的原因),那么不要对数据库服务器进行多次往返(这也是 I/O 绑定在两个级别上,网络 I/O 以及磁盘 I/O)。
因此,获取数据,并将其拆分为块或分区。这一切都在我指出的文章中进行了解释。最简单的实现是块的数量等于机器上核心的数量。
每个块由一个线程处理。
当所有线程都完成后,你就完成了。
利用 .NET 4.0 中线程池的新功能(如果您使用 Parallel.For 或 PLINQ 或任务),您将获得一些其他好处,例如“工作窃取”,以进一步加快工作速度。
我认为 Parallel.For/Parallel.ForEach 很适合你。
EDIT
刚刚注意到 .NET 3.5 要求。这些概念仍然适用,但您没有 Parallel.For/ForEach。因此,这里是一个使用线程池并使用数据并行技术的实现(根据我的博客文章修改)。
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。此方法负责将数据分区为块,因此您不必担心任何问题。只需调用它即可。