Skip to main content
 首页 » 编程设计

c#之线程锁定与创建新对象

2024年02月13日36Free-Thinker

C# lock 语句一次只允许一个线程访问一个对象。 在 Parallel.ForEach 循环中,在循环内创建一个新对象(局部变量)而不是使用字段变量会不会更快,因为那样不会阻塞任何线程? 每种方式的优缺点是什么?

我正在使用下面的代码,似乎创建本地变量而不是在字段上使用锁会稍微快一些。

注意。 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); 
}); 

请您参考如下方法:

使用 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 => {}); 

第二个参数是一个委托(delegate),您可以使用它来创建线程本地数据。在循环的每次迭代中,您将获得本地数据,您可以更改它并返回到下一次迭代。

最后一个参数是另一个将在每个任务结束时调用的委托(delegate)