情景:
我想问这个关于 Parallel.For(或 C#.Net 中的任何其他多线程方法)的问题。我必须构建一个 MultiThreaded Mailer Windows 服务,该服务将尽可能快地向所有收件人发送邮件。我从包含电子邮件消息和 SmtpDetails 的数据库中获取序列化的行,然后在代码中对它们进行反序列化。
一封电子邮件可能有 1000 个收件人,以此类推,一台双核机器(开发机器)至少可以同时运行 2 个线程。所以我使用parallel.For 为了让ro 这样做。我已阅读有关为每个线程运行一次的 LocalInit 委托(delegate)。
代码:
int itemCount = serMailObj.ReceipientList.Count;
Parallel.For(0, itemCount, () =>
{
return new ThreadLocalStateCache()
{
Receipient = serMailObj.ReceipientList.Dequeue(),
mail = serMailObj.Email,
SerializableSmtpDetails = serSmtpObj
};
}
, doWork, (x) => { });
private static ThreadLocalStateCache doWork(int instance, ParallelLoopState state, ThreadLocalStateCache threadInstance)
{
KeyValuePair<string, string> kvp = threadInstance.Receipient;
SerializableSmtpDetails serSmtpObj = threadInstance.SerializableSmtpDetails;
MailMessage email = threadInstance.mail;
email.To.Add(new MailAddress(kvp.Key, kvp.Value));
SmtpClient client = new SmtpClient();
client.Credentials = new System.Net.NetworkCredential(serSmtpObj.UserName, serSmtpObj.Password);
client.Host = serSmtpObj.Host;
client.Port = serSmtpObj.Port;
client.EnableSsl = serSmtpObj.EnableSSL;
try
{
client.Send(email);
Console.WriteLine("sending mail....");
}
catch (Exception)
{
throw;
}
return null;
}
public class ThreadLocalStateCache
{
public KeyValuePair<string, string> Receipient { get; set; }
public MailMessage mail { get; set; }
public SerializableSmtpDetails SerializableSmtpDetails { get; set; }
}
上面的代码非常简单。 localInit 委托(delegate)为每个线程构造一个本地对象。然后 doWork 尝试处理队列。
问题:
请解释我如何隔离每个线程中的邮件和 smtpclient 对象。并处理队列。
编辑 1:如果多线程专家可以帮助我,请告诉我是否有任何方法让每个线程都拥有其局部变量的唯一副本而不是共享的。由于 MailMessage 对象不是不可变的,我也无法创建它的克隆。除了在每个线程中对其进行反序列化(这将确保创建一个新对象)之外,还有什么神奇的方法可以实现这一点吗?
最佳答案
doWork()
可能有问题返回 null
.正如我在回答 your recent comment here 时了解到的那样,线程本地对象应该在 Parallel.For body 的后续调用之间传递在同一个线程,因为它应该作为累加器工作;见 the usage example at MSDN .不清楚返回 null
时会发生什么,但我会解决这个问题,看看它是否有所作为。
关于multithreading - 如何确保线程之间唯一的本地状态以进行电子邮件队列处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5620713/