3

我已经为客户端构建了一个批量电子邮件发送网站,该客户端需要在单个发送中发送80,000封电子邮件。它基本上为发送创建了一个新线程,以便控制权可以交还给用户界面(这样可以加载反馈页面),然后为每个公司创建一个新线程,以便将电子邮件发送给收件人。这些电子邮件都排队,使用此代码:防止多线程网站消耗太多资源

// Loop through the companies and send their mail to the specified recipients 
     // while creating a new thread for each company 
     // A new thread is started so that the feedback page can load 
     SendingThread = Task.Factory.StartNew(() => 
     { 
      // This is a thread safe for loop 
      Parallel.ForEach<CompanyEntity>(companies, company => 
      { 
        // Start a new thread for each company send 
        Task.Factory.StartNew(() => 
        { 
         // Get the recipients for this company 
         var companyRecipients = GetSubscribersForCompany(company.Id, recipients); 

         // Send the newsletter to the company recipients 
         var success = SendNewsletterForCompany(newsletter, company, companyRecipients, language, 
                   version, company.AdvertCollectionViaNewsletterCompanyAdvertLink, newsletter.NewsletterType, email); 

         // Add the status update so the front end can view a list of updated conpany statuses 
         if (success) 
          AddStatusUpdate(company.CompanyTitle + " has completed processing."); 

         // Starts sending the emails if the engine hasn't already been started 
         SendEngine.Start(CurrentSmtpClient, this); 

        }).ContinueWith(antecendent => EndCompaniesSendUpdate(companiesToProcess, companiesProcessed), TaskContinuationOptions.OnlyOnRanToCompletion); 
      }); 
     }, new CancellationToken(), TaskCreationOptions.LongRunning, TaskScheduler.Default); 

虽然电子邮件排队,发送引擎接管并从队列中拉电子邮件,然后使用新的Parallel类并将它们发送:

Action action =() => 
     { 
      MailMessage message; 
      while (queue.TryDequeue(out message)) 
      { 
       SendMessage(sendingServer, message, factory); 
      } 
     }; 

     // Start 5 concurrent actions to send the messages in parallel. 
     Parallel.Invoke(action, action, action, action, action); 

所有这些都很棒,可以在10分钟内发送40,000条新闻。唯一的问题是服务器上的RAM和CPU在这10分钟内100%被占用。这会影响服务器上的其他站点,因为它们无法访问。

有什么办法来限制IIS 7.5中发送应用程序的资源使用情况,或者通过更改上面的代码?

+1

在网站的线程中初始化长时间运行的任务是错误的。这是Windows服务的用途。 – Stilgar 2012-03-09 08:27:19

+1

我不知道你的队列通常是空的还是填充的,但是如果队列为空的话,一段时间(TryDequeue)循环会将内核的寿命从内核吸收掉。您是否有任何理由进行轮询,而不是在此队列上使用适当的信号? – 2012-03-09 09:17:43

+0

@Stilgar不幸的是,我没有预算来重新开发它作为一个Windows服务,但我意识到,我应该看看这样做的前面。 – 2012-03-09 10:57:39

回答

2

问题:

  • 你生成一个并行的foreach中的一个线程,“平行”的一部分意味着它已经产卵的身体线程。您在并行调用中嵌套并行调用,而不是在另一个“调用”内部的并行ForEach内执行“调用”。

  • 你正在一个线程内部运行一个while循环,没有CPU的休息。这是并行调用5x。

答案:

CPU使用率,你需要给你的处理喘息。在你的While TryDequeue循环中放上一个短暂的睡眠。

 MailMessage message; 
     while (queue.TryDequeue(out message)) 
     { 
      SendMessage(sendingServer, message, factory); 
      Thread.Sleep(16); 
     } 

对于RAM和CPU使用情况,您需要一次处理LESS。

 SendingThread = Task.Factory.StartNew(() => 
     { 
      foreach(var company in companies) 
      { 
         // Get the recipients for this company 
         var companyRecipients = GetSubscribersForCompany(company.Id, recipients); 

         // Send the newsletter to the company recipients 
         var success = SendNewsletterForCompany(newsletter, company, companyRecipients, language, 
                   version, company.AdvertCollectionViaNewsletterCompanyAdvertLink, newsletter.NewsletterType, email); 

         // Add the status update so the front end can view a list of updated conpany statuses 
         if (success) 
          AddStatusUpdate(company.CompanyTitle + " has completed processing."); 

         // Starts sending the emails if the engine hasn't already been started 
         SendEngine.Start(CurrentSmtpClient, this); 


      } 
     }, new CancellationToken(), TaskCreationOptions.LongRunning, TaskScheduler.Default); 
+0

啊哈,我虽然Parallel.ForEach只是一个线程安全循环。我没有意识到它是自己的线程。我重写了代码并添加了Thread.Sleep,并将资源使用降至可接受的水平。谢谢。 – 2012-03-15 09:17:33