对不起,标题有点蹩脚,我无法正确地说出来。
编辑:我应该注意这是一个控制台c#app
我已经制作了一个像这样工作的系统原型(这是粗略的伪代码):
var collection = grabfromdb();
foreach (item in collection) {
SendAnEmail();
}
SendAnEmail:
SmtpClient mailClient = new SmtpClient;
mailClient.SendCompleted += new SendCompletedEventHandler(SendComplete);
mailClient.SendAsync('the mail message');
SendComplete:
if (anyErrors) {
errorHandling()
}
else {
HitDBAndMarkAsSendOK();
}
显然这种设置并不理想。如果初始集合有10,000个记录,那么它会以相当短的顺序刷新10,000个smtpclient实例,就像它可以逐步遍历行一样 - 并且可能在此过程中崩溃。
我理想的最终游戏是同时发送10个并发电子邮件。
想到一个hacky解决方案:添加一个计数器,当调用SendAnEmail()时递增,并在发送SendComplete时递减。在初始循环中调用SendAnEmail()之前,检查计数器,如果它太高,则在一段时间内休眠,然后再次检查。
我不确定这是一个如此棒的想法,并认为这样的想法会有办法正确地做到这一点。
我对线程知之甚少,不确定它是否适合在这里使用。例如,在后台线程中发送电子邮件,首先检查子线程的数量,以确保没有太多使用。或者如果内置了某种类型的“线程限制”。
根据Steven A. Lowe的建议,我现在有:
我在使用此设置时遇到了一些问题。我想我已经错过了背景线程的船,我是否应该为词典中的每个项目产生其中一个?如果电子邮件会清空线程结束,我怎么能让线程因为缺少更好的单词而“闲逛”。
我在后台线程中添加了'while(true){}'。如果que为空,则等待几秒钟并再次尝试。如果阙重复为空,我'打破'一会儿,程序结束......工作正常。我有点担心“虽然(真实)”的业务但是......
答案 0 :(得分:2)
使用队列作为有限缓冲区,由其自己的线程处理。
调用fill-queue方法创建一个电子邮件队列,限于(比如说)10。用前10封未发送的电子邮件填写。启动一个线程来处理队列 - 对于队列中的每个电子邮件,将其发送为异步。当队列空了一会儿睡觉并再次检查。让完成委托从队列中删除已发送或错误的电子邮件并更新数据库,然后调用fill-queue方法将更多未发送的电子邮件读入队列(返回到限制)。
您只需要围绕队列操作进行锁定,并且只需管理(直接)一个线程来处理队列。您永远不会有多于N + 1个线程同时处于活动状态,其中N是队列限制。
答案 1 :(得分:1)
我相信你的hacky解决方案实际上会起作用。只需确保在递增和递减计数器的位周围有一个锁定语句:
class EmailSender
{
object SimultaneousEmailsLock;
int SimultaneousEmails;
public string[] Recipients;
void SendAll()
{
foreach(string Recipient in Recipients)
{
while (SimultaneousEmails>10) Thread.Sleep(10);
SendAnEmail(Recipient);
}
}
void SendAnEmail(string Recipient)
{
lock(SimultaneousEmailsLock)
{
SimultaneousEmails++;
}
... send it ...
}
void FinishedEmailCallback()
{
lock(SimultaneousEmailsLock)
{
SimultaneousEmails--;
}
... etc ...
}
}
答案 2 :(得分:1)
我会将所有消息添加到队列中,然后生成10个发送电子邮件的线程,直到队列为空。 Pseudo'ish C#(可能不会编译):
class EmailSender
{
Queue<Message> messages;
List<Thread> threads;
public Send(IEnumerable<Message> messages, int threads)
{
this.messages = new Queue<Message>(messages);
this.threads = new List<Thread>();
while(threads-- > 0)
threads.Add(new Thread(SendMessages));
threads.ForEach(t => t.Start());
while(threads.Any(t => t.IsAlive))
Thread.Sleep(50);
}
private SendMessages()
{
while(true)
{
Message m;
lock(messages)
{
try
{
m = messages.Dequeue();
}
catch(InvalidOperationException)
{
// No more messages
return;
}
}
// Send message in some way. Not in an async way,
// since we are already kind of async.
Thread.Sleep(); // Perhaps take a quick rest
}
}
}
如果邮件相同,只有许多收件人,只需将邮件与收件人交换,然后向Send方法添加一个Message参数。
答案 3 :(得分:0)
您可以使用.NET Timer设置发送消息的计划。每当计时器触发时,抓住接下来的10条消息并将它们全部发送,然后重复。或者,如果您想要一般(每秒10条消息)速率,您可以让计时器每100毫秒触发一次,并且每次都发送一条消息。
如果您需要更高级的计划,可以查看Quartz.NET
等计划框架答案 4 :(得分:0)
这不是Thread.Sleep()
可以处理的东西吗?
你认为背景线程在这里可以起到很好的作用是正确的。基本上你想要做的是为这个进程创建一个后台线程,让它以自己的方式运行,延迟和所有,然后在进程完成时终止线程,或者无限期地保持它(将其转换为Windows服务或类似的东西将是一个好主意。)
一点点intro on multi-threading can be read here (with Thread.Sleep included!)。