2010-05-05 36 views
12

Tôi đã nghiên cứu tính thực tiễn của một số tính năng song song mới trong .Net 4.0.Các tính năng song song trong .Net 4.0

Nói rằng tôi có mã như vậy:

foreach (var item in myEnumerable) 
    myDatabase.Insert(item.ConvertToDatabase()); 

Imagine myDatabase.Insert đang thực hiện một số công việc để chèn vào một cơ sở dữ liệu SQL.

Về mặt lý thuyết bạn có thể viết:

Parallel.ForEach(myEnumerable, item => myDatabase.Insert(item.ConvertToDatabase())); 

Và tự động bạn sẽ có được mã mà lợi dụng đa lõi.

Nhưng nếu myEnumerable chỉ có thể tương tác với một chuỗi đơn lẻ thì sao? Liệu lớp Parallel liệt kê bởi một luồng đơn và chỉ gửi kết quả đến các luồng công nhân trong vòng lặp?

Nếu myDatabase chỉ có thể tương tác với một chuỗi đơn lẻ thì sao? Nó chắc chắn sẽ không tốt hơn nếu tạo kết nối cơ sở dữ liệu cho mỗi lần lặp của vòng lặp.

Cuối cùng, điều gì xảy ra nếu "mục var" của tôi xảy ra là UserControl hoặc nội dung nào đó phải tương tác với chuỗi giao diện người dùng?

Tôi nên làm theo mẫu thiết kế nào để giải quyết những vấn đề này?

Nó đang tìm kiếm với tôi rằng chuyển sang Parallel/PLinq/etc là không chính xác dễ dàng khi bạn đang đối phó với các ứng dụng trong thế giới thực.

Trả lời

12

Giao diện IEnumerable<T> vốn không phải là chủ đề an toàn. Parallel.ForEach sẽ tự động xử lý việc này và chỉ song song các mục sắp ra khỏi điều tra của bạn. (Trình tự sẽ luôn được truyền qua, một phần tử tại một thời điểm, theo thứ tự - nhưng các đối tượng kết quả sẽ được song song.)

Nếu không thể xử lý các lớp của bạn (nghĩa là: T). để song song thói quen này. Không phải mọi trình tự đều là một ứng cử viên cho việc song song - đó là một lý do tại sao nó không được trình biên dịch tự động thực hiện;)

Nếu bạn đang làm việc cần làm việc với chuỗi giao diện người dùng, điều này vẫn có khả năng xảy ra. Tuy nhiên, bạn sẽ cần phải chăm sóc tương tự như bạn sẽ bất cứ lúc nào bạn đang giao dịch với các yếu tố giao diện người dùng trên các chủ đề nền và sắp xếp lại dữ liệu trên luồng giao diện người dùng. Điều này có thể được đơn giản hóa trong nhiều trường hợp bằng cách sử dụng API TaskScheduler.FromCurrentSynchronizationContext mới. Tôi đã viết về this scenario on my blog here.

+1

Câu trả lời tốt nhất cho đến nay, câu hỏi phụ mặc dù: nói vòng lặp cơ thể của tôi thực hiện một hoạt động IO chạy dài (yêu cầu mạng, cơ sở dữ liệu, vv), sẽ lớp Parallel phát hiện ngủ/treo chủ đề và tự động bắt đầu một cái mới? Hay nó sẽ bị giới hạn số lượng lõi trên máy? – jonathanpeppers

+0

@ Jonathan.Peppers: Trình lên lịch tác vụ mặc định xử lý việc này khá tốt. Nó sẽ tiêm thêm công việc vào tình huống. (Theo mặc định, ThreadPool sử dụng nhiều phần tử hơn chủ đề và quy mô trở lại dựa trên khối lượng công việc động) –

2

Như các bạn đã đoán, lợi dụng Parallel.For hoặc Parallel.ForEach đòi hỏi bạn phải có khả năng để soạn công việc của bạn thành các đơn vị rời rạc (thể hiện bằng cách tuyên bố lambda của bạn cũng được truyền cho Parallel.ForEach) có thể được thực hiện một cách độc lập .

+0

Mọi sự cố trong thế giới thực có đáp ứng được tiêu chí này không? Nói cách khác, liệu ứng dụng trung bình có thể sử dụng các tính năng song song này không? – jonathanpeppers

+0

@ Jonathan: Tuyệt đối. Hãy xem bài thuyết trình này của Scott Hanselman, nơi anh ấy cho thấy một ví dụ sinh động về cách thức hoạt động của nó. http://channel9.msdn.com/posts/matthijs/Lap-Around-NET-4-with-Scott-Hanselman/ Cuộc biểu tình bắt đầu lúc 38 phút, 55 giây vào cuộc trò chuyện và kết thúc lúc 47:02. –

+0

Rõ ràng trang web của họ có một số rắc rối bỏ qua đến 38:55, tôi sẽ phải xem toàn bộ điều ở nhà và lấy lại cho bạn. Tôi vẫn hoài nghi rằng họ sẽ đưa ra một ví dụ tốt. – jonathanpeppers

0

có một thảo luận tuyệt vời trong các câu trả lời và nhận xét tại đây: Parallel.For(): Update variable outside of loop.

Trả lời là không: tiện ích mở rộng song song sẽ không suy nghĩ cho bạn. Các vấn đề đa luồng vẫn còn thực tế ở đây. Đây là đường cú pháp đẹp, nhưng không phải là thuốc chữa bách bệnh.

+0

Đó là nhiều hơn một chút so với đường cú pháp.Ví dụ, bạn có thể chỉ định mức độ song song, và treo lên một thói quen hủy bỏ mà sẽ gracefully thư giãn tất cả các chủ đề. –

6

Tất cả những vấn đề này đều là vấn đề hợp pháp - và PLINQ/TPL không tìm cách giải quyết chúng. Nó vẫn là công việc của bạn như là một nhà phát triển để viết mã có thể hoạt động chính xác khi song song. Không có phép thuật nào mà trình biên dịch/TPL/PLINQ có thể làm để chuyển đổi mã không an toàn để đa luồng thành mã an toàn luồng ... bạn phải đảm bảo rằng bạn làm như vậy.

Đối với một số trường hợp bạn đã mô tả, trước tiên bạn nên quyết định xem sự song song có đồng đều hay không. Nếu nút cổ chai sẽ có được kết nối với cơ sở dữ liệu hoặc đảm bảo việc sắp xếp các hoạt động đúng, thì có lẽ đa luồng không phù hợp.

Trong trường hợp TPL phát trực tiếp đến nhiều chủ đề, giả sử của bạn là chính xác. Trình tự được liệt kê trên một chuỗi đơn lẻ và mỗi mục công việc sau đó (có khả năng) được gửi đến một chuỗi riêng biệt sẽ được kích hoạt. Giao diện IEnumerable<T> vốn đã là không phải luồng an toàn, nhưng TPL xử lý cảnh hậu trường này cho bạn.

PLINQ/TPL giúp bạn làm gì, quản lý thời gian và cách gửi công việc tới nhiều chủ đề. TPL phát hiện khi có nhiều lõi trên máy và automaticaly quy mô số lượng các chủ đề được sử dụng để xử lý dữ liệu. Nếu máy chỉ có một CPU/Lõi, thì TPL có thể chọn không được song song với công việc. Lợi ích cho bạn, nhà phát triển, không phải viết hai đường dẫn khác nhau - một cho logic song song, một cho tuần tự. Tuy nhiên, trách nhiệm vẫn là của bạn để đảm bảo rằng mã của bạn có thể được truy cập an toàn từ nhiều chủ đề đồng thời.

Tôi nên làm theo mẫu thiết kế nào để giải quyết những vấn đề này?

Không có câu trả lời cho câu hỏi này ... tuy nhiên, thực tiễn chung là sử dụng immutability trong thiết kế đối tượng của bạn. Tính bất biến làm cho nó an toàn hơn để tiêu thụ một đối tượng trên nhiều chủ đề và là một trong những thực tiễn phổ biến nhất trong việc thực hiện các phép toán song song. Trên thực tế, các ngôn ngữ như F # sử dụng tính bất biến rộng rãi để cho phép ngôn ngữ giúp lập trình đồng thời dễ dàng hơn.

Nếu bạn đang sử dụng .NET 4.0, bạn cũng nên xem các lớp tuyển tập ConcurrentXXX trong System.Collections.Concurrent. Đây là nơi bạn sẽ tìm thấy một số cấu trúc bộ sưu tập khóa không bị khóa và hạt mịn giúp việc viết mã đa luồng trở nên dễ dàng hơn.

0

Đây là câu hỏi rất hay và câu trả lời không rõ ràng 100%/ngắn gọn. Tôi sẽ chỉ cho bạn để tham khảo này từ Micrsoft, nó đưa ra một chút chi tiết như để WHEN you should use the parallel items.

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