线程锁定与创建新对象

时间:2014-01-05 08:06:51

标签: c# multithreading task-parallel-library

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);
});

2 个答案:

答案 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不用作共享资源。所以如果你每次创建新对象都很安全。