2011-11-03 43 views
48

Tôi đang cố chạy nhiều chức năng kết nối với một trang web từ xa (theo mạng) và trả về một danh sách chung. Nhưng tôi muốn chạy chúng cùng một lúc.Parallel.ForEach với việc thêm vào danh sách

Ví dụ:

public static List<SearchResult> Search(string title) 
{ 
    //Initialize a new temp list to hold all search results 
    List<SearchResult> results = new List<SearchResult>(); 

    //Loop all providers simultaneously 
    Parallel.ForEach(Providers, currentProvider => 
    { 
     List<SearchResult> tmpResults = currentProvider.SearchTitle((title)); 

     //Add results from current provider 
     results.AddRange(tmpResults); 
    }); 

    //Return all combined results 
    return results; 
} 

Như tôi đã nhìn thấy nó, chọc kim nhiều lần để 'kết quả' có thể happend cùng lúc ... Mà có thể sụp đổ ứng dụng của tôi.

Làm cách nào để tránh điều này?

+0

Phiên bản .NET bạn đang sử dụng? – sll

+3

Nó sẽ phải có ít nhất .Net 4; Song song đã được giới thiệu ở đó. – arootbeer

Trả lời

36
//In the class scope: 
Object lockMe = new Object();  

//In the function 
lock (lockMe) 
{  
    results.AddRange(tmpResults); 
} 

Về cơ bản, khóa có nghĩa là chỉ có một luồng có thể truy cập vào phần quan trọng đó cùng một lúc.

+0

Nhưng điều gì sẽ xảy ra nếu WHILE những kết quả đó đang được thêm vào kết quả từ một nhà cung cấp khác cố gắng thêm vào? họ sẽ FAIL hoặc WAIT cho đến khi có thể? – shaharmor

+3

Khi có khóa, chủ đề sẽ đợi cho đến khi khóa có thể lấy được khóa. – Haedrian

+0

Vì vậy, về cơ bản nó giống như nói: Chờ cho đến khi results.isLocked, và khi nó tự do khóa nó và viết? – shaharmor

21

Bộ sưu tập đồng thời mới cho .Net 4; chúng được thiết kế để hoạt động với chức năng song song mới.

Xem Concurrent Collections in the .NET Framework 4:

Trước NET 4, bạn phải cung cấp cơ chế đồng bộ hóa của riêng bạn nếu nhiều luồng có thể truy cập vào một bộ sưu tập được chia sẻ duy nhất. Bạn phải khóa bộ sưu tập ...

... các lớp và giao diện [mới] trong System.Collections.Concurrent [được thêm trong .NET 4] cung cấp triển khai nhất quán cho [...] lập trình đa luồng các vấn đề liên quan đến dữ liệu được chia sẻ qua các luồng.

94

Bạn có thể sử dụng concurrent collection.

Các namespace System.Collections.Concurrent cung cấp một số các lớp học tập thread-safe nên được sử dụng ở vị trí của loại tương ứng trong System.CollectionsSystem.Collections.Generic namespace bất cứ khi nào nhiều luồng đang truy cập vào bộ sưu tập đồng thời.

Bạn có thể sử dụng ví dụ ConcurrentBag vì bạn không đảm bảo thứ tự các mục sẽ được thêm vào.

Trình bày một bộ sưu tập các đối tượng an toàn, không có thứ tự.

+3

Điều này sẽ được đánh dấu là câu trả lời! – Misiu

+0

Có, đây là câu trả lời thực tế. Bạn sẽ nhận được hiệu suất tốt hơn (thường) với các bộ sưu tập đồng thời. – lkg

+0

đánh dấu là câu trả lời! – Serdar

10

Điều này có thể được diễn tả ngắn gọn bằng PLINQ của AsParallelSelectMany:

public static List<SearchResult> Search(string title) 
{ 
    return Providers.AsParallel() 
        .SelectMany(p => p.SearchTitle(title)) 
        .ToList(); 
} 
14

Đối với những người thích mã:

public static ConcurrentBag<SearchResult> Search(string title) 
{ 
    var results = new ConcurrentBag<SearchResult>(); 
    Parallel.ForEach(Providers, currentProvider => 
    { 
     results.Add(currentProvider.SearchTitle((title))); 
    }); 

    return results; 
} 
Các vấn đề liên quan