2011-08-15 32 views
8

Bir Görev içinde çalışan bir Parallel.ForEach var. Bir e-posta adresi koleksiyonu üzerinde yinelenir ve SMTP kuyruğuna bir MailMessage gönderir, gönderildikten sonra DB'deki bir tabloyu sonuç olarak günceller.Parallel.ForEn fazla sayıda öğeyi koleksiyonda yineleme Yineleme

DB'de MailMessage'ı sıraya, bazen 6 kata kadar çok kez gönderdiğinizi görebiliyorum. İşte basitleştirilmiş kodum, daha iyi bir yaklaşım önerebilir misiniz?

düğmesi tıklandığında, ben

CampaignManager.Broadcast.BroadcastService broadcastService = new CampaignManager.Broadcast.BroadcastService(); 

     var task = Task<CampaignManager.Broadcast.Results.Broadcast>.Factory.StartNew(() => { 
      return broadcastService.BroadcastCampaign(); 
     }, TaskCreationOptions.LongRunning); 

     Task.WaitAny(task); 

     if (task.Result != null) 
     { 
      Broadcast.Results.Broadcast broadcastResult = task.Result; 
      MessageBox.Show(broadcastResult.BroadcastSent.GroupName + " completed. " + broadcastResult.NumberSuccessful + " sent."); 
     } 

Bu temelde abonelerin (özel sınıf), koleksiyonu üzerinde dolaşır bir ConcurrentBag alır ve bir mesaj gönderir bir görev oluşturur ... Yeni bir Görev oluşturmak .. .

Ben ConcurrentBag en evreli vardır, bu nedenle toplama birden çok kez bazı yineleme nedenlerine emin değilim o inanıyoruz yol
public Results.Broadcast BroadcastCampaign() 
{ 
// Get ConcurrentBag of subscribers 
subscribers = broadcast.GetSubscribers(); 

// Iterate through subscribers and send them a message 
Parallel.ForEach(subscribers, subscriber => 
{ 
    // do some work, send to SMTP queue 

    // Add to DB log 
}); 

// return result 
} 

. Binden azı, koleksiyonun% 10'u için en az 2 mesajını sıraya koyar.

sayesinde

Greg.

+0

Neden bir görev için neden bir paralel oluşturuyorsunuz anlamıyorum. Neden sadece görev olmadan yapmak ve broadcastService.BroadcastCampaign() ;? –

+0

Orada Görevim var, sonuçta, bir kez Parallel.ForEach içinde çalışmak zorunda kaldıktan sonra, yayın hizmeti birkaç saniyede bir ateşleme ile bir Windows servisi olacak, belli ki bir işe ihtiyaç duyuyor, sadece size göstermek için oraya koydum. Görev içinde koşuyordu, son kod buydu. – gfyans

cevap

6

ConcurrentBag'ların iş parçacığı için güvenli olduğuna inanıyorum, bu yüzden neden birkaç kez koleksiyonda yinelenen yineleneceğini emin değilim.

Burada varsayımınız doğrudur. Aslında (ConcurrentBag<T>) GetEnumerator<T> yöntemi (koleksiyonun numaralandırılması için) aslında bu noktada iç koleksiyonun bir kopyasını oluşturur, böylece koleksiyonun bir kopyasının üzerinde durursunuz.

tek abone için birden çok kez çağrıldığını kuyruğu görüyorsanız, bu ConcurrentBag<T> birkaç defaya kadar abone veya ... oluyor diğer bazı sorun olduğunu ekledi anlamına gelir


Ayrı bir notta, burada bir Görev kullanımı gerçekten gerekli değildir. Sadece ek yük ekler (bu durumda özel bir iş parçacığı oluşturur, sonra hemen engeller ve bekler). Sadece çok gibi senin yöntemini çağırmak için bu yeniden yazmak çok daha iyi olacaktır:

CampaignManager.Broadcast.BroadcastService broadcastService = new CampaignManager.Broadcast.BroadcastService(); 

Broadcast.Results.Broadcast broadcastResult = broadcastService.BroadcastCampaign(); 
MessageBox.Show(broadcastResult.BroadcastSent.GroupName + " completed. " + broadcastResult.NumberSuccessful + " sent."); 

sadece hiç yararlı değil hemen üzerinde ( Task.WaitAny) beklemek için bir görev oluşturma. Buna ek olarak, Task.WaitAny(...) kullanmak yerine, başka bir amaç için görev istiyorsanız, görev tamamlanana kadar engellenecek olan broadcastResult = task.Result; numaralı telefonu arayabilirsiniz.

+0

Sanırım başka bir sorun daha var, basit bir foreach veya foreach kullanmak için değiştirirsem, abone başına bir mesaj gönderir (sadece iki kat uzun sürüyor). Yarının etrafındaki kodu değiştireceğim, Görevden kurtulacağım ve ConcurrentBag'ı IEnemurable olarak değiştireceğim (eğer böyle yapıyorsa) ve nasıl gittiğini görün. Geri rapor edecek. – gfyans

+0

@Greg F: İçinde "iş yapıp yapmamanız" işinin iç kısmından emin olmadığına inanıyorum ... –

+0

Evet, haklısın, işin içi güvenli değildi! Bu sabah yeniden çalıştım ve şimdi çalışıyor. Yardım ettiğin için teşekkür ederim. – gfyans