简体   繁体   English

如何在多线程应用程序中安全使用SmtpClient.SendAsync

[英]How to safely use SmtpClient.SendAsync in Multithreaded application

In my application, I am using ActionBlock from Dataflow library, to send out email alerts using SmtpClient.SendAsync() method, which does not block calling thread.( ActionBlock is getting it's data from BufferBlock , and blocks are tied together using bufferBlock.LinkTo(actionBlock) ). 在我的应用程序中,我正在使用Dataflow库中的ActionBlock通过SmtpClient.SendAsync()方法发送电子邮件警报,该方法不会阻止调用线程。( ActionBlockBufferBlock获取数据,并且使用bufferBlock.LinkTo(actionBlock)块绑定在一起bufferBlock.LinkTo(actionBlock) )。 However, this method will throw InvalidOperationException if another .SendAsync() call is in progress. 但是,如果.SendAsync()另一个.SendAsync()调用,则此方法将引发InvalidOperationException

According to MSDN documentation , there is public event SendCompletedEventHandler SendCompleted that is raised when send operation completes. 根据MSDN 文档 ,发送操作完成时会引发public event SendCompletedEventHandler SendCompleted

How do I make sure, that race between threads (or Tasks ) spawned by ActionBlock will not cause InvalidOperationException to be thrown ? 如何确定由ActionBlock产生的线程(或Tasks )之间的争用不会导致引发InvalidOperationException

One thought, I have so far, is to add to my class(that sends out emails) private lock around SendAsync() call and private function that will be assigned to SendCompleted event. 到目前为止,我有一种想法是将围绕SendAsync()调用的私有锁和将分配给SendCompleted事件的私有函数添加到我的类(发送电子邮件)中。 When the thread reaches SendAsync() it obtains the lock, and when the event is raised, private function unlocks the lock, allowing other threads to obtain lock, and progress. 当线程到达SendAsync()它获取锁,并在引发事件时,私有函数将锁解锁,从而允许其他线程获取锁并继续前进。

Create one SmtpClient for each send operation. 为每个发送操作创建一个SmtpClient That way there is no need to synchronize anything. 这样就无需同步任何内容。 Simply enclose it in using to clean up. 只需将其封闭起来即可using

You should simply use SendMailAsync instead. 您应该只使用SendMailAsync It will start with calling SendAsync and complete when SendCompleted is raised. 它将从调用SendAsync开始,并在引发SendCompleted时完成。

To make sure only 1 message is sent at each moment you can use SemaphoreSlim set to 1. It's basically an AsyncLock . 为了确保每次仅发送1条消息,您可以将SemaphoreSlim设置为1。它基本上是AsyncLock

However, this will limit you parallelism as you can only perform one operation at a time. 但是,这将限制您的并行性,因为您一次只能执行一个操作。 You can simply use many different clients. 您可以简单地使用许多不同的客户端。 If not one per call then use some resource pool and then you can have concurrency but still keep each client thread-safe. 如果每个调用都不是,则使用一些资源池,那么您可以具有并发性,但仍保持每个客户端线程安全。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM