2010-05-07 41 views
12

Chúng tôi đang làm việc để giảm độ trễ và tăng hiệu suất của một quá trình được viết bằng Java tiêu thụ dữ liệu (xml strings) từ socket thông qua phương thức readLine() của lớp BufferedReader. Dữ liệu được phân cách bằng dấu phân cách cuối dòng (\ n) và mỗi dòng có thể có độ dài biến đổi (6KBits - 32KBits). mã của chúng tôi trông giống như:Java: Hiệu quả của phương thức readLine của BufferedReader và các lựa chọn thay thế có thể

Socket sock = connection; 
InputStream in = sock.getInputStream(); 
BufferedReader inputReader = new BufferedReader(new InputStreamReader(in)); 
... 
do 
{ 
    String input = inputReader.readLine(); 
    // Executor call to parse the input thread in a seperate thread 
}while(true) 

Vì vậy, tôi có một vài câu hỏi:

  • Liệu inputReader.readLine() phương thức hoàn trả ngay sau khi nó chạm nhân vật \ n hoặc nó sẽ đợi cho đến khi bộ đệm đầy?
  • Có nhanh hơn khi chọn dữ liệu từ ổ cắm hơn là sử dụng bộ đệmBufferedReader không?
  • Điều gì sẽ xảy ra khi kích thước của chuỗi đầu vào nhỏ hơn kích thước bộ đệm nhận của Socket?
  • Điều gì sẽ xảy ra khi kích thước của chuỗi đầu vào lớn hơn kích thước bộ đệm nhận của Socket?

Tôi đang nắm bắt (chậm) với thư viện IO của Java, vì vậy mọi con trỏ đều được đánh giá cao.

Cảm ơn bạn!

+0

Tôi đoán bạn đang sử dụng định dạng dành riêng cho ứng dụng - các dòng mới và khoảng trắng nói chung không có ý nghĩa trong XML. – mdma

+0

Có, xin lỗi phải rõ ràng hơn.Chúng tôi đang tiêu thụ dữ liệu trực tuyến từ một ứng dụng bên ngoài thông qua kết nối TCP. Mỗi thông điệp XML được phân tách bằng ký tự \ n. Tôi cho rằng nó giống hệt nhau để đọc một tập tin tuần tự trong đó mỗi dòng là một tài liệu xml hoàn chỉnh. – Luhar

Trả lời

15

Phương thức inputReader.readLine() sẽ trả về ngay khi nó chạm \ n ký tự hay nó sẽ đợi cho đến khi bộ đệm đầy?

  • Nó sẽ trở lại ngay khi nhận được dòng mới.

Có thể nhận dữ liệu từ ổ cắm nhanh hơn sử dụng BufferedReader không?

  • BufferedReader đòi hỏi phải sao chép dữ liệu. Bạn có thể thử các apis NIO, mà có thể tránh sao chép, nhưng bạn có thể muốn hồ sơ trước khi chi tiêu bất cứ lúc nào về điều này để xem nếu nó thực sự là I/O đó là nút cổ chai.Cách khắc phục nhanh hơn đơn giản là thêm BufferedInputStream xung quanh ổ cắm, để mỗi lần đọc không chạm vào ổ cắm (Không rõ liệu InputStreamReader có thực hiện bất kỳ bộ đệm nào). Ví dụ:

    BufferedReader mới (InputStreamReader mới (BufferedInputStream mới (trong)))

gì sẽ xảy ra khi kích thước của chuỗi đầu vào là nhỏ hơn so với kích thước của bộ đệm nhận của Ổ cắm?

  • BufferedReader sẽ tìm nạp tất cả dữ liệu availalbe. Sau đó nó sẽ quét dữ liệu này để tìm dòng mới. Kết quả là lần đọc tiếp theo có thể đã có dữ liệu trong BufferedReader.

Điều gì xảy ra khi kích thước của chuỗi đầu vào lớn hơn kích thước bộ đệm nhận của Socket?

  • Các BufferedReader sẽ đọc những gì có trong bộ đệm • Nhận, và như không có xuống dòng hoặc cuối dòng được đạt tới, nó sẽ tiếp tục đọc dữ liệu từ các ổ cắm cho đến khi nó tìm thấy EOF hay một dòng mới. Lần đọc tiếp theo có thể chặn cho đến khi có thêm dữ liệu.

Để tổng hợp, BufferedReader chỉ chặn khi thật cần thiết.

+0

Cảm ơn bạn đã trả lời chi tiết. – Luhar

+0

Không phải lo lắng. Tôi hy vọng bạn nhận được hiệu suất được cải thiện mà bạn đang tìm kiếm với các thay đổi được đề xuất. Nếu không, hãy thử profiling, và nếu vẫn không có may mắn, bạn luôn có thể gửi một câu hỏi yêu cầu giúp đỡ với việc cải thiện hiệu suất :-) Chúc may mắn! – mdma

2

Câu trả lời cho câu hỏi đầu tiên của bạn là có và không. Nếu bộ đệm đã chứa trình kết thúc dòng, nó sẽ trả về ngay lập tức, tuy nhiên nếu nó không chứa trình kết thúc thì nó sẽ cố gắng lấp đầy bộ đệm, nhưng không nhất thiết phải đầy đủ. Nó sẽ chỉ đọc cho đến khi có một số dữ liệu mới (ít nhất một char) hoặc EOF đạt được.

Một trong những điều tốt đẹp về java là các thư viện là nguồn mở, vì vậy nếu bạn có một bản sao đầy đủ của JDK, bạn có thể tự tìm nguồn để trả lời các loại câu hỏi này. Tôi sử dụng nhật thực như IDE của tôi và theo mặc định nếu bạn đặt con trỏ lên tên lớp và nhấn F3 nó sẽ đưa bạn đến nguồn (đây là cách tôi nhận được câu trả lời ở trên). Thông báo trước là với việc phân phối chuẩn nguồn cho một số lớp nội bộ/mã gốc không có sẵn.

Đối với câu hỏi thứ hai của bạn, tôi sẽ nói chung là không, vì logic được BufferedReader sử dụng thường là bất kỳ mã nào cần phải tạo lại để đạt được cùng một tác vụ. Điều duy nhất có thể làm chậm BufferedReader là nội bộ nó sử dụng một StringBuffer, được đồng bộ hóa, thay vì StringBuilder không đồng bộ.

3

Một trong những ưu điểm của BufferedReader là nó cung cấp một lớp tách (bộ đệm) giữa các phương thức nhập (đọc, readLine, v.v.) mà bạn sử dụng và socket thực đọc, vì vậy bạn không phải lo lắng về tất cả các trường hợp như "phần lớn dòng nằm trong bộ đệm, nhưng bạn cần phải đọc một bộ đệm khác để lấy \ n" v.v.

Bạn đã thực hiện phép đo hiệu suất chỉ ra rằng việc sử dụng BufferedReader là một vấn đề hiệu suất cho ứng dụng của bạn? Nếu không, tôi khuyên bạn nên bắt đầu bằng cách chọn phương thức nhập cung cấp chức năng bạn muốn (đầu vào dựa trên dòng được chấm dứt bởi \ n, từ âm thanh của nó) và lo lắng nếu có cách "nhanh hơn" để thực hiện chỉ khi bạn tìm thấy phương thức nhập liệu là một nút cổ chai.

Nếu đầu vào dựa trên dòng thực sự là những gì bạn đang theo dõi, bạn sẽ sử dụng một số loại bộ đệm như BufferedReader, vậy tại sao lại phát minh ra bánh xe này?

+1

Cảm ơn bạn đã trả lời. Chúng tôi đã thực hiện một số lượng đáng kể hồ sơ trên ứng dụng và chúng tôi phát hiện ra rằng có thể có sự chậm trễ một vài phần nghìn giây khi xử lý các tin nhắn nhỏ. Với tài liệu API của BufferedReader, nó dường như không có ý nghĩa gì cả! Chúng tôi đã tắt thuật toán Nagle bằng cách đặt cờ TcpNoDelay và đang xem các giải pháp thay thế khác. – Luhar

+0

Thú vị. BufferedReader chắc chắn sẽ liên quan đến một bản sao bổ sung của dữ liệu, nhưng thật khó để xem làm thế nào mà có thể mất mili giây ... –

0

Nếu bạn biết mã hóa ký tự của dữ liệu đến, bạn có thể muốn viết lớp của riêng bạn thực hiện đọc dữ liệu nhị phân, tìm kiếm trình kết thúc cuối dòng cụ thể của bạn. Điều này có thể loại bỏ rất nhiều mã hóa/giải mã và sao chép không cần thiết. Đảm bảo bạn triển khai thứ gì đó có bộ đệm có thể sử dụng lại (ví dụ: các lớp học CharBuffer hoặc ByteBuffer của NIO sẽ xuất hiện hoặc được khởi tạo chính xác StringBuilder nếu bạn cần String trường hợp). Hãy chắc chắn rằng bạn đã có đủ không gian trong bộ đệm, 32Ki đến 64Ki là không có gì cho các máy tính hiện tại.

Khi bạn đã nhận dữ liệu trong vùng chứa có thể sử dụng, bạn có thể sử dụng bất kỳ mẹo nào trong sách (nhiều chủ đề, thực thi, v.v.) để xử lý dữ liệu hiệu quả. Hãy nhớ rằng, cách duy nhất để làm chậm CPU hiện tại là nhấn bộ nhớ cache - bộ dữ liệu lớn/động, sao chép giả - hoặc nhánh - vòng không cần thiết, câu lệnh if và các cuộc gọi hạt nhân và I/O khác.

+0

Và McAfee, McAfee chậm * tất cả mọi thứ * xuống để thu thập dữ liệu: ( –

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