3

한 번의 전송으로 80,000 개의 이메일을 전송해야하는 클라이언트를위한 대량 메일 전송 웹 사이트를 구축했습니다. 기본적으로 보내기 용 새 스레드를 만들어 컨트롤을 UI에 다시 전달할 수 있으므로 (피드백 페이지가로드 될 수 있음) 전자 메일을받는 사람에게 전자 메일을 보내기 위해 각 스레드마다 새 스레드가 만들어집니다. 이메일이 대기하는 동안, 송신 엔진은 점거하고 큐에서 이메일을 끌어 다음 새 병렬 클래스 사용하여 전송멀티 스레드 웹 사이트에서 너무 많은 리소스를 사용하지 못하도록 방지

// 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); 

:

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

+1

대기열이 비어 있거나 채워져 있는지 여부는 알 수 없지만 대기열이 비어 있으면 잠깐 (TryDequeue) 루프가 코어에서 빠져 나간다. 이 대기열에서 적절한 신호를 사용하는 대신 폴링하는 이유가 있습니까? –

+0

@Stilgar 불행히도, 저는 Windows 서비스로 재개발 할 예산이 없습니다. 그러나 나는 아마 그렇게하는 것을보아야한다고 생각합니다. –

답변

2

문제 :

  • 당신은 병렬 foreach는 내부 스레드를 생성하는은 "병렬"부분은 이미 몸에 스레드를 산란을 의미합니다. 다른 작업 내부에서 병렬 ForEach 내부의 작업 대신 병렬 호출을 중첩합니다.

  • CPU에 대한 휴식없이 쓰레드 내부에서 while 루프를 실행하고 있습니다. 그것은 Parallel Invoked 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을 추가 했으므로 리소스 사용이 허용 수준까지 떨어졌습니다. 감사. –

관련 문제