2011-12-05 20 views
7

Sorum şu ki, aşağıdaki kodda, örnek yöntemlerin benim çalıştığımı düşündüğüm değişkenlere erişebileceğinden emin olabilir miyim, yoksa hala çalışıyorken başka bir iş parçacığı tarafından değiştirilebiliyor olabilir ? Kapatmaların bununla bir ilgisi var mı, yani IEnumerable<T>'un yerel bir kopyası üzerinde çalışıyorum, böylece numaralandırma güvenli midir?Çoklu öge, lambda ve yerel değişkenler

Sorumu açıklamak gerekirse, paylaşılan değişkenlere hiç yazmamam gereken kilitlere ihtiyacım var mı?

public class CustomerClass 
{ 
    private Config cfg = (Config)ConfigurationManager.GetSection("Customer"); 

    public void Run() 
    { 
     var serviceGroups = this.cfg.ServiceDeskGroups.Select(n => n.Group).ToList(); 

     var groupedData = DataReader.GetSourceData().AsEnumerable().GroupBy(n => n.Field<int>("ID")); 
     Parallel.ForEach<IGrouping<int, DataRow>, CustomerDataContext>(
      groupedData, 
      () => new CustomerDataContext(), 
      (g, _, ctx) => 
      { 
       var inter = this.FindOrCreateInteraction(ctx, g.Key); 

       inter.ID = g.Key; 
       inter.Title = g.First().Field<string>("Title"); 

       this.CalculateSomeProperty(ref inter, serviceGroups); 

       return ctx; 
      }, 
      ctx => ctx.SubmitAllChanges()); 
    } 

    private Interaction FindOrCreateInteraction(CustomerDataContext ctx, int ID) 
    { 
     var inter = ctx.Interactions.Where(n => n.Id = ID).SingleOrDefault(); 

     if (inter == null) 
     { 
      inter = new Interaction(); 
      ctx.InsertOnSubmit(inter); 
     } 

     return inter; 
    } 

    private void CalculateSomeProperty(ref Interaction inter, IEnumerable<string> serviceDeskGroups) 
    { 
     // Reads from the List<T> class instance variable. Changes the state of the ref'd object. 
     if (serviceGroups.Contains(inter.Group)) 
     { 
      inter.Ours = true; 
     } 
    } 
} 
+0

CustomerDataContext'in uygulamasını paylaşabilir misiniz? Bu, bir veri yarışının şu anda meydana gelebileceği tek yer gibi gözüküyor. –

+0

CustomerDataContext, standart bir Entity Framework DataContext'tir ve aslında iş parçacığı yereldir, bu nedenle orada hiçbir veri yarışması yoktur. –

cevap

3

cevabı ve bu süreçte de soruyu bulmuş görünüyor. Gerçek soru, eşzamanlı erişim için gerçekten nesneler olduğu ortaya çıkan yerel "değişkenlerin" güvenilir olup olmadığıydı. Cevabınız hayır, eğer iplik güvenli bir şekilde ele alınmayan içsel duruma sahipse, tüm bahisler kapalıdır. Kapatma yardımcı olmaz, sadece söz konusu nesneye bir referans yakalar.

Benim özel durumda

- foreach her çağrı, Contains(), Where() vb yepyeni IEnumerator alır çünkü eşzamanlı sadece görünür olan bu aslında parçacığı güvenli, IEnumerable<T> okur ve hiçbir kendisine yazıyor İstenen iş parçacığı. Bununla birlikte, başka herhangi bir nesne de tek tek kontrol edilmelidir.

Yani, yaşasın, benim için kilit yok veya senkronize koleksiyonları :)

sayesinde @ebb ve doğrudan soruya cevap vermedi rağmen @Dave, doğru yönde beni işaret etti. Sonuçlardan ilgileniyorsanız


, bu art arda işlem süresini simüle etmek Thread.SpinWait ile benim ev PC (bir dört çekirdekli) bir çalışma var. Gerçek uygulama, yerel ağda SQL Server ile çift çekirdekli hiper iş parçacıklı makinede neredeyse 2 kat (01:03 vs 00:34) bir gelişme gösterdi.

Singlethreaded Tek iş parçacıklı, foreach kullanarak. Nedenini bilmiyorum, ancak çok sayıda çapraz çekirdekli bağlam anahtarı var.

Multithreaded Parallel.ForEach'u kullanarak, gereken yerlerde iş parçacığı ile kilitleyin.

1

Şu anda, Ne söyleyebilirim, sizin örnek yöntemler herhangi bir üye değişkenleri kullanmıyorsanız dan. Bu onları vatansız ve dolayısıyla threadafe yapar. Ancak, aynı durumda, kod netliği ve küçük bir performans avantajı için onları "statik" olarak işaretlemeniz daha iyi olur.

Bu örnek yöntemler bir üye değişkeni kullanıyorlarsa, o zaman bu değişken olarak yalnızca threadafe olarak olurlar (örneğin, basit bir liste kullandıysanız, bunlar threadafe olmaz ve garip davranışlar görürsünüz). Uzun hikaye kısa, üye değişkenleri kolay iplik güvenliği düşmanıdır.

İşte refactor'um (yasal uyarı, test edilmemiş). Geçirilen verileri sağlamak istiyorsanız, bunları parametre olarak geçirirseniz ve bunları üye değişken olarak saklamıyorsanız daha iyi davranırsınız:

GÜNCELLEME: Salt okunur listeye başvurmak için bir yol sormuşsunuzdur. Bunu ekledim ve statik etiketleri çıkardım (böylece örnek değişkeni paylaşılabilir).

public class CustomerClass 
{ 

private List<string> someReadOnlyList; 

    public CustomerClass(){ 
     List<string> tempList = new List<string>() { "string1", "string2" }; 
     someReadOnlyList = ArrayList.Synchronized(tempList); 
    } 

    public void Run() 
    { 
     var groupedData = DataReader.GetSourceData().AsEnumerable().GroupBy(n => n.Field<int>("ID")); 

     Parallel.ForEach<IGrouping<int, DataRow>, CustomerDataContext>(
      groupedData, 
      () => new CustomerDataContext(), 
      (g, _, ctx) => 
      { 
       var inter = FindOrCreateInteraction(ctx, g.Key); 

       inter.ID = g.Key; 
       inter.Title = g.First().Field<string>("Title"); 

       CalculateSomeProperty(ref inter); 

       return ctx; 
      }, 
      ctx => ctx.SubmitAllChanges()); 
    } 

    private Interaction FindOrCreateInteraction(CustomerDataContext ctx, int ID) 
    { 
     var query = ctx.Interactions.Where(n => n.Id = ID); 

     if (query.Any()) 
     { 
      return query.Single(); 
     } 
     else 
     { 
      var inter = new Interaction(); 
      ctx.InsertOnSubmit(inter); 
      return inter; 
     } 
    } 

    private void CalculateSomeProperty(ref Interaction inter) 
    { 
     Console.Writeline(someReadOnlyList[0]); 
     //do some other stuff 
    } 
} 
+0

Cevabınız için teşekkürler :) Ancak, bu listeye yazmam ama sadece ondan okuyorsam? İkinci yöntem olan 'CalculateSomeProperty()' bu listeden 'nolu kısmı görüntülemesine rağmen, hiçbir zaman eklememekte ya da çıkarmamaktadır. Tüm sınıftan görülebilmesi daha kolaydır, çünkü diğer yöntemlerin buna ihtiyacı vardır. –

+0

@VladislavZorov, 'ReadOnlyCollection' - http://msdn.microsoft.com/en-us/library/ms132474.aspx – ebb

+0

hatta' Listesini okuma görünüyor Yani '(veya' ReadOnlyCollection ') bir parçacığı değil Güvenli operasyon. Ancak, "Genel statik (Visual Basic'te Paylaşılan) üyeleri bu cümleyi güvenlidir" cümlesi anlayamıyorum "? Niye ya? –

İlgili konular