5

Ngày tốt,Parallel.ForEach đã lỗi thời. cũ, ra khỏi thời trang?

Thực hiện song song có thể đạt được thông qua nhiều cách. Từ nghiêm ngặt hướng dẫn sử dụng "đa luồng" để sử dụng "người giúp đỡ" khác nhau được tạo ra bởi Microsoft. Một trong những người trợ giúp đó là lớp Parallel.

Một trong các đồng nghiệp của tôi khẳng định rằng Parallel.ForEach (hoặc lớp Parallel tổng thể) là "cũ" và không nên được sử dụng. Thay vào đó, ông nói, người ta nên sử dụng các hoạt động không đồng bộ. Nói cách khác, bạn nên sử dụng Task.WhenAll() thay vì Parallel.ForEach().

Khi được hỏi tại sao không sử dụng Parallel.ForEach(), khi điều này là chính xác những gì là cần thiết - nhiều hoạt động tốn kém thực hiện song song, ông trả lời rằng Parallel.ForEach() là cũ và rằng Microsoft khuyến cáo sử dụng async/chờ đợi bất cứ nơi nào có thể.

Tôi đã tìm kiếm trên MSDN và Stackoverflow và ở khắp mọi nơi tôi có thể nhưng tôi không thể tìm thấy bất cứ điều gì trỏ đến sự cần thiết của việc sử dụng async/await thay vì .Parallel. Mặc dù bạn thường có thể đạt được kết quả tương tự bằng cách thay đổi các công cụ này nhưng không có nghĩa là Parallel.ForEach đã lỗi thời. Hay không?

Bất kỳ ai có liên kết đến một số "thực hành tốt nhất" hoặc "đề xuất" của một cơ quan có uy tín (MSDN?) Có thể nói rằng Parallel.ForEach() đang bị loại bỏ và cần phải tuân theo việc tạo, chạy và chờ nhiệm vụ?

Vui lòng không đăng câu trả lời liên quan đến Parallel VS Async vì đây không phải là câu hỏi.

Câu hỏi đặt ra là: Vì bạn có thể làm nhiệm vụ chạy song song sử dụng async/chờ đợi WhenAll (WaitAll vv), nó làm cho lớp 'Parallel' lỗi thời, cũ, hoặc không thời trang trong .NET 4.5 trở đi?

+7

Nếu anh ấy tuyên bố rằng "Microsoft đề xuất" thì anh ấy sẽ có thể hiển thị đề xuất đó. Tôi chưa từng thấy một thứ như vậy. –

+2

Bạn bè của bạn là khó hiểu song song với không đồng bộ. – dcastro

+0

@ JonSkeet bạn thấy tôi không muốn hỏi anh ta bằng chứng trước khi tôi thực sự làm nghiên cứu của tôi cho tôi không muốn xuất hiện thù địch. Điều gì sẽ xảy ra nếu câu trả lời của bạn (hoặc một số khác) giống như "chắc chắn, mọi người đều biết nó đã lỗi thời - chúng tôi chỉ giữ nó ở đó cho những người già"? – agfc

Trả lời

5

Tôi không nghĩ rằng Parallel.ForEach đã lỗi thời.

Kể từ khi giới thiệu Thư viện song song nhiệm vụ (TPL) với .NET 4, Microsoft có distinguished between "Data Parallelism" (e.g. Parallel.ForEach) and "Task Parallelism" (Task). Từ MSDN:

  • "song song dữ liệu đề cập đến kịch bản trong đó các hoạt động tương tự được thực hiện đồng thời (có nghĩa là, song song) trên các yếu tố trong một bộ sưu tập nguồn hoặc mảng."
  • "[T] yêu cầu song song đề cập đến một hoặc nhiều tác vụ độc lập chạy đồng thời".

(Nhấn mạnh của tôi Giống như dcastro commented (above):. "người bạn của bạn là xử lý song song khó hiểu với sự không đồng bộ.")

Hai loại song song/đồng thời theo đuổi mục tiêu khác nhau, do đó TPL cung cấp các khả năng khác nhau cho mỗi người trong số họ.

Khái niệm, Task.WhenAll thuộc về thể loại song song nhiệm vụ, vì vậy tôi không nghĩ rằng nó bị ám ảnh một cái gì đó thuộc về thể loại song song khác (dữ liệu song song).

+0

Cảm ơn bạn. Trong trường hợp của tôi, tôi gọi mutiple các cuộc gọi bên ngoài đến các nguồn khác nhau. Những cuộc gọi đó hoàn toàn độc lập với nhau. Tuy nhiên tôi không thể tiến hành trước khi tất cả chúng được thực hiện. Cả hai Parallel.ForEach và Task.WhenAll làm việc tốt ở đây. Tuy nhiên, tôi thấy rằng ParallelForEach là thanh lịch hơn và liên quan đến mã ít hơn. Nhận của anh ta là có, có lẽ nó không nhất thiết phải sai khi sử dụng nó, nhưng phương thức ưa thích là Task.WhenAll(). – agfc

+0

@AlexeiFimine: Một số lời khuyên chung về sự khác biệt của ý kiến: Hỏi đồng nghiệp của bạn * tại sao * ông tuyên bố rằng 'Task.WhenAll' được ưa thích. Mặc dù thường không có quyền rõ ràng và sai trong các trường hợp như vậy, mọi người sẽ có thể sao lưu hợp lý các khiếu nại của họ. (Xem [bình luận của Jon Skeet ở trên.] (Http: // stackoverflow.com/questions/29919727/29919803 # comment47960546_29919727)) Nếu đối số của anh ấy thuyết phục bạn (nghĩa là chúng "tốt hơn" so với ý kiến ​​hiện tại của bạn), hãy thay đổi mã của bạn. Nếu bạn nghĩ rằng bạn có đối số tốt hơn ("mã thanh lịch hơn với Parallel.ForEach"), hãy ở lại với phiên bản mã của bạn. – stakx

2

Parallel.ForEach (và PLINQ nói chung) có các khả năng không có sẵn trong hỗ trợ ngôn ngữ async.

Ví dụ: bạn có thể giới hạn mức độ song song (ví dụ: 100 mục cần xử lý, nhưng không thể thực hiện nhiều hơn 10 mục cùng một lúc). Vì vậy nó không phải là lỗi thời.

Về cơ bản async là về thực hiện các hoạt động đồng thời - không có bất kỳ giả định nào về luồng - dễ viết hơn. PLINQ là về tính toán sử dụng nhiều lõi.

Tôi nghi ngờ đồng nghiệp của bạn đang đọc quá nhiều vào việc sử dụng trực tiếp Thư viện song song nhiệm vụ (TPL) phần lớn là không cần thiết với async bằng ngôn ngữ (ngoại trừ loại trả về của async chức năng). Nhưng PLINQ luôn là một lớp khác trên TPL. Nếu bất cứ điều gì PLINQ và async là hai cách riêng biệt để sử dụng TPL cho các mục đích khác nhau.

+0

Tốt nhất với DegreeOfParallelism. Tôi đã luôn thấy nó hữu ích theo cách nó được thực hiện. Đôi khi tôi thậm chí sẽ sử dụng nó để thử nghiệm và gỡ lỗi như trong #If Debug .DegreeOfParallelism = 1 – agfc

2

asyncawait không có gì liên quan đến song song. Chúng là các công nghệ được sử dụng để tạo các API không đồng bộ hiện có dễ dàng hơn để tiêu thụ và hiển thị. asyncawait không khởi tạo song song hoặc đồng thời. Trong thực tế, await kết thúc song song bằng cách đợi một thứ đang chạy.

Parallel.ForEach được sử dụng để xử lý một tập hợp các mục đồng nhất theo cùng cách trên nhiều lõi. Bạn có thể mô phỏng Parallel.ForEach bằng cách sinh ra một số lượng lớn nhiệm vụ. Không có lợi thế trong việc đó. Trong thực tế, nó giới thiệu sự thiếu hiệu quả và làm xáo trộn mã. Nó có thể và hoạt động nhưng nó là một cách kém hơn để làm việc nếu Parallel.ForEach được áp dụng.

Tôi nghĩ đồng nghiệp của bạn không hiểu rằng chờ đợi thực sự chỉ chờ đợi. Nó không bắt đầu một cái gì đó.

Sử dụng song song. * Và PLINQ (chủ yếu) cho công việc liên kết CPU.

+1

đang chờ Task.WhenAll (IEnumerable Tasks) sẽ thực sự khởi chạy tất cả các tác vụ trong bộ sưu tập Nhiệm vụ song song và sau đó đợi tất cả chúng hoàn thành. Thiết kế này thực hiện chính xác những gì ParallelForEach sẽ làm. Tuy nhiên, để đạt được điều đó, tôi cần tạo danh sách các tác vụ đó theo cách thủ công. Ngoài ra còn có vấn đề "thoát khỏi async". Có vẻ trực quan hơn và sạch sẽ hơn khi sử dụng Parallel.ForEach trong trường hợp của tôi. – agfc

+0

@AlexeiFimine ** Không! ** Nó sẽ làm những gì tên nói. Nó chờ đợi. Các nhiệm vụ phải đang chạy .; Nhưng kết luận của bạn là đúng: Tại sao quản lý các nhiệm vụ cho công việc CPU bị ràng buộc khi bạn chỉ có thể sử dụng song song. – usr

+0

@AlexeiFimine Những nhiệm vụ đó là * có thể *, nhưng không nhất thiết phải bắt đầu khi chúng được tạo lần đầu tiên. 'Task.WhenAll' không khởi động chúng, và' await' cũng vậy, như chúng ta đã chỉ ra. Hoàn toàn không đảm bảo rằng các tác vụ đó sẽ được xử lý song song, cũng không phải chúng thực sự không đồng bộ - cho tất cả chúng ta biết, chúng có thể được thực hiện đồng bộ và tuần tự. Một lần nữa, tất cả những gì đang chờ đợi là chờ đợi. – dcastro

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