2012-07-09 40 views
7

Tôi mới bắt đầu sử dụng TPL và tôi muốn thực hiện một số cuộc gọi đến các dịch vụ web diễn ra song song. Từ những gì tôi có thể thu thập, tôi thấy hai cách để làm điều này.Điều gì sẽ là cách tốt hơn để sử dụng thư viện song song nhiệm vụ

Hoặc Parallel.ForEach:

List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere. 
     Parallel.ForEach(list, member => 
      { 
       var result = Proxy.Invoke(member); 
       //... 
       //Do stuff with the result 
       //... 
      }); 

Hoặc Task<T>:

List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere. 
     ForEach(var member in list) 
     { 
      Task<MemberResult>.Factory.StartNew(() => proxy.Invoke(member)); 
     } 

     //Wait for all tasks to finish. 
     //Process the result objects. 

Bất chấp nếu cú ​​pháp là đúng hay không, đều này để equivilant?

Chúng có tạo ra cùng một kết quả không? Nếu không, tại sao? và đó là thích hợp hơn?

Trả lời

5

Đối với mã và trường hợp sử dụng mà bạn thảo luận, hai cách tiếp cận về cơ bản là tương đương.

Parallel.ForEach rất hữu ích khi bạn phải phân vùng phạm vi nhập trên nhiều tác vụ (không áp dụng ở đây), hoặc dễ dàng đồng bộ hóa kết quả của một số hoạt động độc lập song song (có thể áp dụng ở đây?).

Trong mọi trường hợp, bạn đã lưu ý rằng trong trường hợp Parallel.ForEach, bạn không phải đồng bộ hóa thủ công việc chờ hoàn thành, trong khi nếu bạn bắt đầu nhiệm vụ theo cách thủ công, bạn phải tự mình quản lý đồng bộ hóa. Trong trường hợp này, bạn có thể sử dụng một cái gì đó như Task.WaitAll(...).

+0

Cảm ơn bạn đã trả lời. Tôi đã kết thúc bằng cách sử dụng Parallel.ForEach và chúng tôi thấy một sự cải thiện khoảng 25% trong thời gian phản ứng trên sản xuất của chúng tôi - 16 lõi máy.Tôi đoán rằng hầu hết các lợi ích là trong xử lý dữ liệu song song, và không phải trong các cuộc gọi song song với các dịch vụ web mình. –

1

Không phản ánh hoặc nhìn vào đầu ra, tôi không thể nói chắc chắn liệu hai thiết bị có giống nhau hay không; tuy nhiên tôi sẽ nghi ngờ nếu họ có nhiều khác biệt. Các câu hỏi về đó là tốt hơn là chủ quan tùy thuộc vào kịch bản. Để trả lời cái nào thích hợp hơn nữa, trong kịch bản bạn cung cấp tôi sẽ nói rằng tôi thích Parallel.ForEach vì tôi có thể đọc nó nhưng nếu nhóm phát triển của bạn không được sử dụng cho thư viện song song thì phiên bản thứ hai là một trong những đi cho.

1

Giữa hai phần mã, Parallel.ForEach() sẽ hiệu quả hơn vì nó xử lý nhiều mục trong một đơn Task, cái khác.

Nhưng cả hai người trong số họ sẽ sử dụng nhiều chủ đề như ThreadPool sẽ cho phép họ, đó không phải là ý tưởng hay trong trường hợp này. Đó là bởi vì các ThreadPool là tốt tại đoán số lượng tối ưu của chủ đề nếu bạn có rất ngắn, CPU ràng buộc Task s, đó là xa trường hợp ở đây.

Do đó, tôi nghĩ rằng lựa chọn tốt nhất là để tự hạn chế mức độ song song cho một số ít (bạn sẽ phải đo để tìm ra những số cho kết quả tốt nhất):

List<ServiceMemberBase> list = …; //Take list from somewhere. 
Parallel.ForEach(list, new ParallelOptions { MaxDegreeOfParallelism = 10 }, 
member => 
{ 
    var result = Proxy.Invoke(member); 
    //... 
    //Do stuff with the result 
    //... 
}); 

Thậm chí hiệu quả hơn sẽ là nếu bạn có thể thực hiện cuộc gọi dịch vụ web không đồng bộ. Làm điều đó và hạn chế mức độ song song cùng một lúc không phải là rất dễ dàng, trừ khi bạn đang ở trên C# 5. Nếu bạn đang ở trên C# 5 và nếu bạn cũng cập nhật Proxy để hỗ trợ Mô hình không đồng bộ dựa trên nhiệm vụ (TAP), bạn có thể sử dụng TPL Dataflow để thực thi mã của bạn hiệu quả hơn:

var actionBlock = new ActionBlock<ServiceMemberBase>(
    async member => 
    { 
     var result = await Proxy.InvokeAsync(member); 
     //... 
     //Do stuff with the result 
     //... 
    } 
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }); 
Các vấn đề liên quan