2008-10-25 41 views
7

Tôi từng viết một Trình thu thập thông tin trong .NET. Để cải thiện khả năng mở rộng của nó, tôi đã cố gắng tận dụng API không đồng bộ của .NET..NET KHÔNG CÓ Giao tiếp Socket Asynchronouos đáng tin cậy?

System.Net.HttpWebRequest có API không đồng bộ BeginGetResponse/EndGetResponse. Tuy nhiên, cặp API này chỉ để nhận tiêu đề phản hồi HTTP và phiên bản Luồng từ đó chúng tôi có thể trích xuất nội dung phản hồi HTTP. Vì vậy, chiến lược của tôi là sử dụng BeginGetResponse/EndGetResponse để nhận được luồng phản hồi một cách không đồng bộ, sau đó sử dụng BeginRead/EndRead để nhận không đồng bộ các byte từ thể hiện Luồng phản hồi.

Mọi thứ có vẻ hoàn hảo cho đến khi Trình thu thập thông tin kiểm tra căng thẳng. Dưới kiểm tra căng thẳng, trình thu thập thông tin bị sử dụng bộ nhớ cao. Tôi đã kiểm tra bộ nhớ với WinDbg + SoS và tiết lộ rằng rất nhiều mảng byte được pined bởi System.Threading.OverlappedData trường hợp. Sau một số tìm kiếm trên internet, tôi tìm thấy KB http://support.microsoft.com/kb/947862 này từ microsoft.

Theo KB, số I/O không đồng bộ phải có "giới hạn trên", nhưng nó không cho biết giá trị giới hạn "được đề xuất". Vì vậy, trong mắt tôi, KB này không giúp gì cả. Đây rõ ràng là một lỗi .NET. Cuối cùng, tôi phải bỏ ý tưởng để thực hiện giải nén byte không đồng bộ từ luồng phản hồi và chỉ thực hiện theo cách đồng bộ.

Thư viện .NET cho phép Asynchronous IO với dấu chấm socket ròng (Socket.BeginSend/ Socket.BeginReceive/ NetworkStream.BeginRead/ NetworkStream.BeginWrite) phải có một ràng buộc trên vào lượng bộ đệm nổi bật (gửi hoặc nhận) với IO không đồng bộ của chúng.

Ứng dụng mạng phải có giới hạn trên trên số lượng xuất sắc IO không đồng bộ mà nó đăng.

Chỉnh sửa: Thêm một số dấu hỏi.

Bất kỳ ai có bất kỳ trải nghiệm nào để thực hiện I/O không đồng bộ trên Socket & NetworkStream? Nói chung, trình thu thập thông tin trong sản xuất có làm I/O với Internet có Đồng bộ hoặc Không đồng bộ không?

+0

Không phải là dấu hỏi sigle ngoại trừ trong chủ đề ... Dấu hiệu xấu. –

Trả lời

3

Bạn rõ ràng muốn giới hạn số lượng yêu cầu đồng thời, bất kể trình thu thập thông tin của bạn có đồng bộ/asynch hay không. Giới hạn đó không cố định, nó phụ thuộc vào phần cứng, mạng của bạn, ...

Tôi không chắc chắn câu hỏi của bạn ở đây là .NET thực hiện HTTP/Sockets là "ok". Có một số lỗ (Xem my post về việc kiểm soát thời gian chờ chính xác), nhưng nó hoàn thành công việc (chúng tôi có trình thu thập thông tin sản xuất tìm nạp ~ hàng trăm trang mỗi giây).

BTW, chúng tôi sử dụng IO đồng bộ, chỉ vì mục đích thuận tiện. Mỗi tác vụ đều có một chuỗi và chúng tôi giới hạn số lượng chuỗi đồng thời. Đối với quản lý chuỗi, chúng tôi đã sử dụng Microsoft CCR.

+0

Tôi không có nghi ngờ rằng I/O đồng bộ trên Socket hoạt động tốt trong DotNet. Tôi chỉ không tin vào API I/O không đồng bộ của nó. –

+0

Vấn đề là hủy bỏ/hủy bỏ ops, nó không bao giờ hoạt động tốt trong .NET. Bạn nên luôn luôn thích API đồng bộ (với thời gian chờ), theo cách này bạn không cần phải tự mình hủy bản thân. – ripper234

+0

Tôi cũng khuyên bạn nên bọc WebRequest đồng bộ trong một Tác vụ. Ngoài ra, không sử dụng Threads, nhưng Tasks - nó sẽ bảo vệ bạn khỏi việc mở rộng Thread-Generation bằng cách sử dụng Threadpool. Nếu bạn sử dụng bổ sung một TaskCancelationSource, bạn có thể hủy dễ dàng chạy Tasks – spookycoder

10

Hmya, đây không phải là vấn đề về khung công tác .NET. Bài báo KB được liên kết có thể đã rõ ràng hơn một chút: "bạn đang sử dụng một khẩu súng được nạp, đây là những gì sẽ xảy ra khi bạn nhắm nó vào chân". Các viên đạn trong khẩu súng đó là .NET cho bạn khả năng bắt đầu càng nhiều yêu cầu I/O không đồng bộ như bạn dám. Nó sẽ làm những gì bạn yêu cầu nó làm, cho đến khi bạn nhấn một số loại giới hạn tài nguyên. Trong trường hợp này, có thể, có quá nhiều pin được nhận bộ đệm trong đống 0 thế hệ.

Quản lý tài nguyên vẫn còn rất nhiều công việc của chúng tôi chứ không phải .NET. Nó không khác với việc cấp phát bộ nhớ mà không bị ràng buộc. Giải quyết vấn đề cụ thể này yêu cầu bạn đặt giới hạn về số lượng các yêu cầu BeginGetResponse() chưa hoàn thành. Có hàng trăm người trong số họ có ý nghĩa rất ít, mỗi người trong số họ phải bóp qua từng chiếc Intertube. Việc thêm một yêu cầu khác sẽ khiến cho mất nhiều thời gian hơn để hoàn thành. Hoặc phá vỡ chương trình của bạn.

+0

Nhưng, làm thế nào tôi có thể nói "giới hạn trên" trong chương trình của tôi? Thực tế là .NET không phát hành mảng byte được ghim ngay cả khi ứng dụng đã hủy bỏ thao tác BeginXXX sau khi hết thời gian chờ. Tôi vẫn tin rằng đây là lỗi .net. –

+0

Không thể xem đây là câu trả lời hữu ích như thế nào ?! –

+1

Gọi EndXxxx để giải phóng tài nguyên là yêu cầu ** cứng **. Đừng bỏ qua điều đó. Rõ ràng là dễ dàng bỏ qua một cách tình cờ khi bạn thực hiện một kế hoạch thời gian chờ. –

0

Không có bài viết KB nào có thể cho bạn giới hạn trên. Giới hạn trên có thể khác nhau tùy thuộc vào phần cứng có sẵn - phần trên của máy bộ nhớ 2G sẽ khác với máy có 16g ram. Nó cũng sẽ phụ thuộc vào kích thước của đống GC, làm thế nào phân mảnh nó là vv

Những gì bạn cần làm là đưa ra một số liệu của riêng bạn bằng cách sử dụng lại các tính toán phong bì. Tìm ra số lượng trang bạn muốn tải xuống mỗi phút. Điều đó sẽ xác định có bao nhiêu yêu cầu không đồng bộ mà bạn muốn xuất sắc (N).

Khi bạn đã biết N, hãy tạo một đoạn mã (như kết thúc tiêu dùng của một đường ống tiêu dùng của nhà sản xuất) có thể tạo N yêu cầu tải xuống không đồng bộ xuất sắc. Ngay sau khi yêu cầu kết thúc (hoặc do thời gian chờ hoặc do thành công), hãy khởi chạy một yêu cầu không đồng bộ khác bằng cách kéo một workitem từ hàng đợi.

Bạn cũng cần đảm bảo rằng hàng đợi không vượt quá giới hạn, ví dụ: tải xuống trở nên chậm chạp vì bất kỳ lý do gì.

0

Điều này xảy ra khi bạn sử dụng phương thức Sendync (BeginSend) không đồng bộ của ổ cắm. Nếu bạn sử dụng threadpool tùy chỉnh của riêng bạn và gửi dữ liệu qua chuỗi với phương thức Gửi được đồng bộ hóa, chủ yếu là giải quyết vấn đề này. Thử nghiệm và chứng minh.

3

Điều này không giới hạn ở .Net. Đây là một thực tế đơn giản là mỗi yêu cầu không đồng bộ (tệp, mạng, v.v.) sử dụng bộ nhớ và (tại một số điểm, đối với yêu cầu mạng ít nhất) không phải nhóm phân trang (xem here để biết chi tiết về các sự cố bạn có thể nhận được trong mã không được quản lý). Do đó, số lượng yêu cầu chưa xử lý được giới hạn bởi số lượng bộ nhớ. Pre-Vista có một số giới hạn hồ bơi không được phân trang nghiêm trọng sẽ khiến bạn gặp vấn đề trước khi hết bộ nhớ, nhưng trong môi trường hậu vista thì tốt hơn nếu sử dụng không phân trang (xem here). Đó là một chút phức tạp hơn trong mã được quản lý như, ngoài các vấn đề bạn nhận được trong thế giới không được quản lý, bạn cũng phải đối phó với thực tế là bộ nhớ đệm bạn sử dụng cho các yêu cầu không đồng bộ được ghim cho đến khi các yêu cầu đó hoàn tất. Có vẻ như bạn đang gặp phải những vấn đề này với lần đọc, nhưng nó tệ, nếu không tệ hơn, để viết (ngay khi điều khiển luồng TCP khởi động kết nối, những lần hoàn thành gửi sẽ bắt đầu mất nhiều thời gian hơn và do đó những bộ đệm đó được ghim lâu hơn và lâu hơn - xem herehere).

Vấn đề không phải là công cụ async .Net bị hỏng, chỉ là trừu tượng hóa sao cho nó trông dễ dàng hơn nhiều so với thực tế. Ví dụ: để tránh sự cố ghim, hãy cấp phát tất cả các bộ đệm của bạn trong một khối đơn kề nhau lớn, bắt đầu chương trình thay vì theo yêu cầu ...

Cá nhân tôi sẽ viết trình thu thập thông tin đó vào mã không được quản lý, nhưng đó là chỉ mình tôi;) Bạn sẽ vẫn phải đối mặt với nhiều vấn đề, nhưng bạn có nhiều quyền kiểm soát hơn đối với họ.

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