【问题标题】:How to safely use SmtpClient.SendAsync in Multithreaded application如何在多线程应用程序中安全地使用 SmtpClient.SendAsync
【发布时间】:2015-02-20 18:52:14
【问题描述】:

在我的应用程序中,我正在使用来自 Dataflow 库的 ActionBlock,使用 SmtpClient.SendAsync() 方法发送电子邮件警报,该方法不会阻止调用线程。(ActionBlock 正在从 BufferBlock 获取数据,并阻止使用bufferBlock.LinkTo(actionBlock) 绑定在一起)。但是,如果另一个 .SendAsync() 调用正在进行,此方法将抛出 InvalidOperationException

根据 MSDN documentation,发送操作完成时会引发 public event SendCompletedEventHandler SendCompleted

我如何确保ActionBlock 产生的线程(或Tasks)之间的竞争不会导致InvalidOperationException 被抛出?

到目前为止,我的一个想法是在我的班级(发送电子邮件)中添加 SendAsync() 调用和将分配给 SendCompleted 事件的私有函数的私有锁定。当线程到达SendAsync() 时,它获得锁,当事件引发时,私有函数解锁锁,允许其他线程获得锁,并继续。

【问题讨论】:

    标签: c# .net multithreading task-parallel-library tpl-dataflow


    【解决方案1】:

    为每个发送操作创建一个SmtpClient。这样就不需要同步任何东西。只需将其附在using 中即可清理。

    【讨论】:

      【解决方案2】:

      您应该直接使用SendMailAsync。它将从调用SendAsync 开始,并在引发SendCompleted 时完成。

      为确保每次只发送 1 条消息,您可以将 SemaphoreSlim 设置为 1。它基本上是 AsyncLock

      但是,这会限制您的并行性,因为您一次只能执行一项操作。您可以简单地使用许多不同的客户端。如果每次调用都不是一个,则使用一些资源池,然后您可以进行并发,但仍保持每个客户端线程安全。

      var client = _smtpClientPool.Get();
      try
      {
          await client.SendMailAsync(...)
      }
      finally
      {
          _smtpClientPool.Put(client);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 1970-01-01
        • 2010-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多