2011-12-05 37 views
7

Câu hỏi của tôi là, trong đoạn mã dưới đây, tôi có thể chắc chắn rằng các phương thức thể hiện sẽ truy cập vào các biến mà tôi nghĩ, hoặc chúng có thể bị thay đổi bởi một chuỗi khác trong khi tôi vẫn đang làm việc ? Việc đóng cửa có liên quan đến điều này không, tức là tôi sẽ làm việc trên một bản sao cục bộ của IEnumerable<T> vì vậy việc liệt kê có an toàn không?Đa luồng, lambdas và biến cục bộ

Để diễn giải câu hỏi của tôi, tôi có cần bất kỳ khóa nào nếu tôi không bao giờ viết cho các biến được chia sẻ không?

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

Bạn có thể chia sẻ việc triển khai CustomerDataContext không? Đây có vẻ là nơi duy nhất mà một cuộc đua dữ liệu hiện có thể xảy ra. –

+0

CustomerDataContext là một DataContext của Entity Framework chuẩn và thực sự là một luồng địa phương, do đó không có các cuộc đua dữ liệu ở đó. –

Trả lời

3

Tôi dường như đã tìm thấy câu trả lời và trong quá trình này, cũng là câu hỏi.

Câu hỏi thực sự là liệu "biến" cục bộ, hóa ra là đối tượng thực sự, có thể được tin cậy để truy cập đồng thời hay không. Câu trả lời là không, nếu chúng xảy ra có trạng thái bên trong không được xử lý theo cách an toàn, tất cả các phiên cược sẽ bị tắt. Việc đóng cửa không giúp đỡ, nó chỉ chụp một tham chiếu đến đối tượng đã nói.

Trong trường hợp cụ thể của tôi - đồng thời đọc từ IEnumerable<T> và không ghi vào nó, nó thực chủ đề an toàn, bởi vì mỗi cuộc gọi đến foreach, Contains(), Where() vv được một tươi mới IEnumerator, mà chỉ có thể nhìn thấy từ chuỗi đã yêu cầu. Bất kỳ đối tượng khác, tuy nhiên, cũng phải được kiểm tra, từng người một.

Vì vậy, hoan hô, không có ổ khóa hoặc bộ sưu tập đồng bộ đối với tôi :)

Nhờ @ebb và @ Dave, mặc dù bạn không trả lời câu hỏi trực tiếp, bạn chỉ cho tôi đi đúng hướng.


Nếu bạn quan tâm đến kết quả, đây là một hoạt động trên máy tính của tôi ở nhà (một quad-core) với Thread.SpinWait để mô phỏng thời gian xử lý của một hàng. Ứng dụng thực sự đã cải thiện gần 2X (01:03 vs 00:34) trên máy siêu luồng lõi kép với SQL Server trên mạng cục bộ.

Singlethreaded Đơn luồng, sử dụng foreach. Tôi không biết tại sao, nhưng có một số lượng khá cao của chuyển mạch bối cảnh đa lõi.

Multithreaded Sử dụng Parallel.ForEach, không có khóa với chỉ đường chính khi cần.

1

Ngay bây giờ, từ những gì tôi có thể biết, phương pháp thể hiện của bạn không sử dụng bất kỳ biến thành viên nào. Điều đó làm cho họ không quốc tịch và do đó an toàn. Tuy nhiên, trong trường hợp tương tự đó, bạn nên đánh dấu chúng là "tĩnh" cho độ rõ ràng của mã và một lợi ích hiệu suất nhỏ.

Nếu các phương pháp cá thể đó sử dụng biến thành viên, thì chúng chỉ là luồng an toàn như biến đó (ví dụ, nếu bạn sử dụng danh sách đơn giản, nó sẽ không phải là luồng an toàn và bạn có thể thấy hành vi lạ). Dài câu chuyện ngắn, biến thành viên là kẻ thù của an toàn chủ đề dễ dàng.

Đây là trình cấu trúc lại của tôi (tuyên bố từ chối trách nhiệm, không được kiểm tra). Nếu bạn muốn cung cấp dữ liệu được chuyển vào, bạn sẽ ở trạng thái an toàn hơn nếu bạn chuyển chúng dưới dạng tham số và không giữ chúng dưới dạng biến thành viên:

CẬP NHẬT: Bạn đã yêu cầu cách tham khảo danh sách chỉ đọc của bạn Tôi đã thêm vào đó và loại bỏ các thẻ tĩnh (để biến thể hiện có thể được chia sẻ).

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

Cảm ơn bạn đã trả lời :) Tuy nhiên, nếu tôi không viết thư cho danh sách đó nhưng chỉ đọc từ nó? Phương thức thứ hai, 'CalculateSomeProperty()' tìm kiếm một số nội dung từ 'List ' này, tuy nhiên không bao giờ thêm hoặc loại bỏ nó. Nó dễ dàng hơn để có thể nhìn thấy nó từ cả lớp, bởi vì các phương pháp khác cần nó. –

+0

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

+0

Vì vậy, có vẻ như ngay cả đọc' Danh sách '(hoặc' ReadOnlyCollection ') không phải là một luồng- Hoạt động an toàn. Tuy nhiên tôi không thể hiểu câu "Công cộng tĩnh (chia sẻ trong Visual Basic) thành viên của loại này là thread an toàn"? Tại sao? –

Các vấn đề liên quan