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

标签 c# multithreading task-parallel-library

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)

关于c# - 线程锁定与创建新对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20931439/

相关文章:

c# - 预加载下一个 IEnumerable<T> 值

.net - 同步上下文的切换是否意味着工作将在拥有同步上下文的线程上运行?

c# - 如何在 C# 中的 GUI 线程上启动一系列定时事件?

c# - 值不能为空。参数名称 : String

c# - Selenium WebDriver 使用代理用户名和密码自动登录

java - 多线程、带有停止和继续信号的多处理

linux - 进程优先级与线程优先级

.net - TransactionScope 和多线程

c# - 检查 Dictionary 的值是否包含具有特定字段值的元素

c# - 如何判断一个类型是否为 HashSet 类型以及如何强制转换?