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