C#lock语句一次只允许一个线程访问一个对象。 在Parallel.ForEach循环中,在循环中创建新对象(局部变量)而不是使用字段变量会更快,因为这样就没有线程被阻塞了吗? 每种方式的利弊是什么?
我正在使用下面的代码,似乎创建一个局部var而不是在字段上使用锁定会稍快一些。
NB。 toEmails变量中有3个电子邮件字符串。
//Method 1 with lock statement takes 14092ms
List<string> toEmails = getListOfToEmails();
Object locker = new object();
SmtpClient smtpClient = getSmtpObject();//smtpClient is used here as a field
Parallel.ForEach(toEmails, toEmail =>
{
string emailBody = getEmailBody(toEmail);
MailMessage mailMessage = getMailMesssageObject(emailBody, toEmail);
lock (locker)
{
smtpClient.Send(mailMessage);
}
});
//Method 2 without lock statement (creating a new local var each iteration) takes 13947ms
List<string> toEmails = getListOfToEmails();
Parallel.ForEach(toEmails, toEmail =>
{
SmtpClient smtpClient = getSmtpObject();//smtpClient is used here as a local var
string emailBody = getEmailBody(toEmail);
MailMessage mailMessage = getMailMesssageObject(emailBody, toEmail);
smtpClient.Send(mailMessage);
});
答案 0 :(得分:4)
使用ForEach
的重载:
Parallel.ForEach(toEmails, () => getSmtpObject() , (toEmail, state, smtp) =>
{
SmtpClient smtpClient = smtp;
string emailBody = getEmailBody(toEmail);
MailMessage mailMessage = getMailMesssageObject(emailBody, toEmail);
smtpClient.Send(mailMessage);
return smtp;
}, smtp => {});
第二个参数是一个委托,您可以使用它来创建线程本地数据。在循环的每次迭代中,您将获得本地数据,您可以更改它并返回到下一次迭代。
最后一个参数是另一个委托,它将在每个任务结束时被调用
答案 1 :(得分:0)
如果有共享资源,最好使用简单锁定。在您的情况下,很简单,SMTP CLIENT不用作共享资源。所以如果你每次创建新对象都很安全。