限制电子邮件发送过程的速度

Cha*_*adT 6 c# multithreading smtpclient

对不起,标题有点糟糕,我无法正确地说出来.

编辑:我应该注意这是一个控制台c#app

我已经制作了一个像这样工作的系统原型(这是粗略的伪代码):

var collection = grabfromdb();

foreach (item in collection) {
    SendAnEmail();
}
Run Code Online (Sandbox Code Playgroud)

发送电子邮件:

SmtpClient mailClient = new SmtpClient;
mailClient.SendCompleted += new SendCompletedEventHandler(SendComplete);
mailClient.SendAsync('the mail message');
Run Code Online (Sandbox Code Playgroud)

SendComplete:

if (anyErrors) {
    errorHandling()
}
else {
    HitDBAndMarkAsSendOK();    
}
Run Code Online (Sandbox Code Playgroud)

显然这种设置并不理想.如果初始集合有10,000个记录,那么它将以相当短的顺序刷新10,000个smtpclient实例,因为它可以逐步执行 - 并且可能在此过程中呈现.

我理想的最终游戏是同时发送10个并发电子邮件.

想到一个hacky解决方案:添加一个计数器,在调用SendAnEmail()时递增,并在发送SendComplete时递减.在初始循环中调用SendAnEmail()之前,检查计数器,如果它太高,则在一段时间内休眠,然后再次检查.

我不确定这是一个如此伟大的想法,并认为SO蜂巢的思想将有办法正确地做到这一点.

我对线程知之甚少,不确定它是否适合在这里使用.例如,在后台线程中发送电子邮件,首先检查子线程的数量,以确保没有太多使用.或者如果内置了某种类型的"线程限制".


更新

根据Steven A. Lowe的建议,我现在有:

  • 一个字典,包含我的电子邮件和一个唯一的密钥(这是电子邮件队列
  • 填充字典的FillQue方法
  • ProcessQue方法,它是后台线程.它检查que和SendAsycs中的任何电子邮件.
  • SendCompleted委托,用于从que中删除电子邮件.并再次调用FillQue.

我对这个设置有一些问题.我想我已经错过了背景线程的船,我是否应该为词典中的每个项目产生其中一个?如果电子邮件que清空线程结束,我怎么能让线程因为缺少更好的单词而"闲逛".


最后更新

我在后台线程中放了一个'while(true){}'.如果que为空,则等待几秒钟并再次尝试.如果阙重复为空,我'打破'一会儿,程序结束......工作正常.我有点担心'虽然(真)'的业务但是......

Ste*_*owe 2

简答

使用队列作为有限缓冲区,由其自己的线程处理。

长答案

调用 fill-queue 方法来创建电子邮件队列,限制为(例如)10 封。用前 10 封未发送的电子邮件填充该队列。启动一个线程来处理队列 - 对于队列中的每封电子邮件,异步发送。当队列为空时,休眠一段时间,然后再次检查。让完成委托从队列中删除已发送或有错误的电子邮件并更新数据库,然后调用 fill-queue 方法将更多未发送的电子邮件读入队列(备份到限制)。

您只需要围绕队列操作进行锁定,并且只需管理(直接)一个线程来处理队列。您永远不会同时有超过 N+1 个线程处于活动状态,其中 N 是队列限制。