2014-09-22 20 views
7

Trong .NET 4.5, có nhiều phương pháp hiện có trong các cặp không đồng bộ và không đồng bộ, chẳng hạn như Flush()FlushAsync(). Lý tưởng nhất I/O tương tác sẽ luôn luôn là không đồng bộ nếu có thể (bạn luôn có thể chặn với .Wait() nếu bạn thực sự muốn), nhưng không async (chặn) các phiên bản rõ ràng là cần phải duy trì do khả năng tương thích ngược.các phương pháp không đồng bộ và không đồng bộ trong thư viện mới

Khi triển khai một thư viện hoàn toàn mới không có hạn chế tương thích ngược, có bất kỳ lý do gì khiến một thư viện sẽ bao gồm các phương pháp không đồng bộ không?

+1

Tôi cho rằng đây là một chút ý kiến ​​(vì nếu bạn chỉ quá tải chúng bằng cách chờ đợi trong quá trình thực hiện của bạn hơn là không có gì có thể đạt được) nhưng tôi sẽ bao gồm những thứ đó - không cần buộc người dùng của bạn không đồng bộ nếu anh ta không muốn (không có vấn đề nếu lý do của mình là tốt hay xấu) - nhưng đây chỉ là ý kiến ​​* của tôi * (node.js mọi người sẽ có một hoàn toàn khác nhau) - đây là lý do tại sao câu hỏi của bạn có thể bị đóng sớm - có thể không có câu trả lời tốt – Carsten

+0

I đừng nghĩ rằng đó chỉ là vấn đề của ý kiến ​​... Tôi chắc chắn có một số loại hướng dẫn hoặc thực hành tốt nhất ở đâu đó. Sau đó, một lần nữa thực hành tốt nhất là một ý kiến, vì vậy có lẽ chúng ta không nên yêu cầu thực hành tốt nhất trên Stack Overflow? – Gigi

+0

@Gigi có lẽ bạn nên hỏi * điều này * trên Meta;) - Tôi chỉ muốn cung cấp cho bạn một gợi ý tại sao bạn có 2 lá cờ gần ngay bây giờ - không phải để tranh luận – Carsten

Trả lời

0

Lý do duy nhất là nếu bạn muốn các ứng dụng hỗ trợ nhắm mục tiêu Khuôn khổ .NET trước 4.5. Nếu bạn có các ứng dụng như vậy và bạn muốn sử dụng thư viện mới của mình thì bạn buộc phải sử dụng cách không đồng bộ.

Bạn có thể biên dịch bản lắp ráp mới của mình bằng .NET 4.0 bằng cách sử dụng Async Targeting Package.. Làm điều đó tôi đề nghị bạn tạo hai dự án: một với 4.5 và một với 4.0.

+0

Thực ra, 4.0 cũng tốt mà không có ATP, bạn không thể sử dụng 'await'. Tất nhiên điều đó có nghĩa là rất khó để có được những điều đúng, nhưng tôi đã bị buộc phải làm điều đó nhiều lần rồi, và nó hoạt động. Và tất nhiên, nếu bạn đã có 'đang chờ đợi' trong thư viện của bạn, người tiêu dùng của bạn cũng sẽ phải là 4/4.5, vì vậy việc thực hiện các phiên bản không đồng bộ sẽ không giúp ích gì. – Luaan

6

Các phương pháp không đồng bộ thường có chi phí liên kết với chúng vì có một máy trạng thái được tạo bởi trình biên dịch dẫn đến một chút mã bổ sung. Nếu bạn không sử dụng các phương pháp async, chúng sẽ không bị phạt do đó bạn tránh được chi phí đó.

Nếu bạn sử dụng phiên bản async và chỉ cần gọi Wait() bạn đang mạo hiểm một deadlock và cũng có thể bạn sẽ phải chịu một bối cảnh chuyển đổi thêm một lần hoạt động async hoàn tất. Vì vậy, tổng thể kết quả sẽ thực hiện một chút tồi tệ hơn.

Ngoài ra, bất kỳ ngoại lệ nào bạn nhận được giờ đây sẽ được bao bọc trong AggregatedException do đó cũng sẽ có thêm công việc trong xử lý ngoại lệ. Hãy xem Async Performance: Understanding the Costs of Async and Await

+2

Đây là một điểm tốt, tuy nhiên, bạn nên nhớ rằng tất cả các chi phí đó hầu như luôn tầm thường so với yêu cầu I/O cơ bản. Vì vậy, sử dụng I/O không đồng bộ là tốt và dandy, khá nhiều bất cứ lúc nào (sau khi tất cả, bạn đang làm như vậy khi thực hiện ví dụ như File.ReadAllBytes - nó chỉ xảy ra trong một lớp thấp hơn). Sử dụng nó cho CPU làm việc vv là đắt hơn, tuy nhiên, có * là * một hướng dẫn chống lại làm cho phương pháp 'XXXAsync' chỉ quấn một mã đồng bộ trong' Task.Run', vì vậy nếu bạn đang làm công việc không đồng bộ thích hợp, chi phí isn ' t xấu. – Luaan

+0

Điều này thực sự rất thú vị. Nhưng nếu phương pháp không async không thể chỉ đơn giản là bọc phương thức async, thì làm thế nào để bạn thực hiện cả hai mà không cần sao chép mã? – Gigi

+0

@Gigi Vâng, nó không nhất thiết phải sao chép mã, nhưng vâng, bạn sẽ không "sử dụng lại" mã. Nếu bạn chỉ đơn giản là thực hiện một 'Wait' trên phương thức async (hoặc' Task.Run' trên phương thức đồng bộ, thì hãy cấm: D), không có điểm nào trong phương thức đó. Có một cái nhìn tại.Mã nguồn tham chiếu NET, bạn có thể xem cách mã hoạt động với ví dụ: 'FileStream' (có một số phương thức đồng bộ/đồng bộ phức tạp) hoặc' Socket' (khá thẳng về phía trước). – Luaan

4

Câu trả lời của Ned khá tốt, vì vậy tôi sẽ không lặp lại những gì anh ấy nói (mặc dù lưu ý rằng phí trên không nhất thiết phải lớn so với chi phí hoạt động I/O).

Một lý do quan trọng nữa để cung cấp các phương thức đồng bộ thực sự rõ ràng trong tầm nhìn - mọi người gặp khó khăn nghiêm trọng khi hiểu các hoạt động không đồng bộ. Chúng được sử dụng để làm "Đọc, sau đó viết, sau đó đọc lại ..." Lỗi xử lý, lỗi địa phương, đồng bộ hóa ... tất cả có thể rất khó khăn rất dễ dàng, đặc biệt là nếu bạn không thể sử dụng await.

Sự thật là, trong khi nó sẽ rất tốt đẹp nếu mọi thứ trở nên không đồng bộ theo thời gian, sẽ khó hơn nhiều để giải thích về các ứng dụng không đồng bộ. Nó vẫn còn tốt hơn so với làm đa luồng, nhưng không phải bởi một toàn bộ rất nhiều.

Bằng cách này, việc sử dụng các phương pháp không đồng bộ có thể được xem là tối ưu hóa - và bạn không thực hiện tối ưu hóa trừ khi bạn biết chúng sẽ giúp đáng kể. Đối với một thư viện, điều này là khó khăn để quyết định - do đó cung cấp cả hai tùy chọn. Người nào đó viết một máy chủ thông lượng cao sẽ thực hiện việc chăm sóc cần thiết để viết một ứng dụng không đồng bộ có hiệu suất và đáng tin cậy. Một người nào đó chỉ cần viết một CMS đơn giản, ví dụ, có thể muốn tránh nó hoàn toàn.

này áp dụng đặc biệt cho C#/NET dưới 4.5 -. Thử làm xử lý trên continuations không đồng bộ lỗi không await, và bạn sẽ thấy những gì tôi đang nói về :)

đang Giữ đơn giản là rất quan trọng. Nó làm giảm chi phí phát triển và bảo trì đáng kể, và làm cho nó dễ hiểu hơn cho người mới đến.

4

Có sự khác biệt nhỏ (hầu như không đáng kể) giữa async và các phiên bản đồng bộ nhưng tôi cho rằng không còn lý do nào để có cả hai phiên bản của cùng một thao tác. Bạn nên quyết định trong quá trình thực hiện thư viện của bạn phiên bản nào phù hợp nhất. Thao tác không đồng bộ tự nhiên (ví dụ: tải xuống tệp) phải là async và các hoạt động liên kết CPU phải đồng bộ.

Bạn có thể thấy mô hình đang được sử dụng trong khuôn khổ WinRT:

Để đạt được những mục tiêu đó, chúng tôi đã nhiều tiềm năng I/O-bound API không đồng bộ trong Windows Runtime. Đây là những ứng cử viên có khả năng nhất để làm giảm hiệu suất rõ ràng nếu được viết đồng bộ (ví dụ: có thể mất nhiều thời gian hơn 50 mili giây để thực thi). Cách tiếp cận không đồng bộ này với API giúp bạn viết mã nhanh và linh hoạt theo mặc định và tăng cường tầm quan trọng của phản hồi ứng dụng trong phát triển ứng dụng kiểu Metro.

Từ Keeping apps fast and fluid with asynchrony in the Windows Runtime

Nó từng là trường hợp đó bằng cách sử dụng quá tải không đồng bộ là vô cùng khó khăn và phức tạp hơn những đồng bộ do đó, có cả hai phiên bản là một ý tưởng tốt. Với async-await không còn là trường hợp.

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