2010-10-27 16 views
5

Tôi đang làm việc trên một ứng dụng Android (trong Java, rõ ràng) và gần đây tôi đã cập nhật mã trình đọc UDP của mình. Trong cả hai phiên bản, tôi thiết lập một số bộ đệm và nhận được một gói tin UDP:Các lớp Java ByteBuffer/IntBuffer/ShortBuffer có nhanh không?

byte[] buf = new byte[10000]; 
short[] soundData = new short[1000]; 
DatagramPacket packet = new DatagramPacket (buf, buf.length); 
socket.receive (packet); 

Trong phiên bản ban đầu, tôi đặt các dữ liệu lại với nhau một byte tại một thời điểm (nó thực sự là 16 PCM dữ liệu âm thanh):

for (int i = 0; i < count; i++) 
    soundData[i] = (short) (((buf[k++]&0xff) << 8) + (buf[k++]&0xff)); 

Trong phiên bản cập nhật, tôi đã sử dụng một số công cụ Java mát tôi không biết về khi tôi bắt đầu:

bBuffer = ByteBuffer.wrap (buf); 
sBuffer = bBuffer.asShortBuffer(); 
sBuffer.get (soundData, 0, count); 

Trong cả hai trường hợp, "đếm" đang được dân cư một cách chính xác (tôi đã kiểm tra). Tuy nhiên, dường như có vấn đề mới với âm thanh phát trực tuyến của tôi - có lẽ nó không được xử lý đủ nhanh - điều này không có ý nghĩa gì với tôi. Rõ ràng, mã đệm được biên dịch thành nhiều hơn ba câu lệnh của mã JVM, nhưng nó chắc chắn có vẻ giống như một giả định hợp lý khi tôi bắt đầu điều này rằng phiên bản thứ 2 sẽ nhanh hơn phiên bản thứ nhất.

Bằng sáng chế, tôi không nhấn mạnh rằng mã của tôi ĐÃ sử dụng bộ đệm Java NIO, nhưng thoạt nhìn ít nhất, nó có vẻ giống như một 'betta' để giải quyết vấn đề này.

Bất kỳ ai có bất kỳ đề xuất nào cho trình đọc UDP Java nhanh, đơn giản và liệu có một "cách tốt nhất" được chấp nhận chung không ??

Cảm ơn, R.

+0

NIO không có ý định nhanh hơn IO "bình thường", nó chỉ có khả năng mở rộng hơn. – skaffman

+0

'đánh cắp cú pháp' Lol là bạn nghiêm túc? Google đã đánh cắp cú pháp java nhiều như một tác giả viết cú pháp tiếng Anh – Falmarri

+0

@Tim Bender phải làm gì với câu hỏi này? Có thể có sự khác biệt giữa vvik Dalvik so với tiêu chuẩn jvm, nhưng nói chung nếu mọi thứ đang chậm trong jvm họ có khả năng cũng được làm chậm trên Android. Bạn có một số kiến ​​thức về sự khác biệt có thể ảnh hưởng đến trường hợp cụ thể này không? –

Trả lời

1

Nói chung, làm việc với các kiểu dữ liệu trực tiếp sẽ là hiệu quả hơn làm việc với các đối tượng vì bạn tránh được một số các chi phí của việc tạo ra các đối tượng, các cuộc gọi chức năng, vv

Có nhiều lý do để sử dụng các đối tượng tiện ích khác ngoài tốc độ: tiện lợi, an toàn, v.v.

Cách tốt nhất để kiểm tra sự khác biệt trong trường hợp cụ thể này là thực sự đo lường nó. Hãy thử cả hai phương pháp với một tập dữ liệu lớn và thời gian nó. Sau đó, bạn có thể quyết định xem nó có xứng đáng với các lợi ích trong trường hợp này hay không.

Bạn cũng có thể sử dụng trình thu thập của Android để xem vấn đề của bạn thực sự ở đâu. Xem TraceView.

+0

Tôi dường như đã xúc động một cuộc chiến tôn giáo ... Xin lỗi về điều đó, và cảm ơn sự hợp lý. – Rich

+0

Một số nội dung của NIO khá là kinh khủng vào lúc này. Các cải tiến đã được thực hiện và sẽ bắt đầu hiển thị trong các bản phát hành trong tương lai. Trong thời gian đó, "kiểm tra & đo lường" là một câu trả lời hay. – fadden

0

Tôi sẽ sử dụng DataInputStream cho tác vụ này, được bao bọc xung quanh một ByteArrayInputStream quấn quanh mảng byte. Đóng gói sự dịch chuyển trong readShort() mà không có các chi phí của ByteBuffer.

Hoặc bạn có thể đọc trực tiếp vào DirectByteBuffer qua DatagramChannel, thay vì sử dụng DatagramPacket & DatagramSocket. Hiện tại bạn đang sử dụng một hỗn hợp của java.net và java.nio.

Tôi không mong đợi sự khác biệt về hiệu suất chính giữa hai cách tiếp cận này, nhưng tôi hy vọng cả hai sẽ nhanh hơn phương pháp lai của bạn.

+0

* Đóng gói sự dịch chuyển trong readShort() mà không có các chi phí của ByteBuffer. * ReadShort có nhiều chi phí hơn so với hoạt động tương tự của số nhiều ByteBuffer – bestsss

+0

@bestsss: 'overheads': đặc biệt là chi phí tạo ra. Đó là những gì tôi đang đề cập đến. – EJP

+0

trực tiếp ByteBuffer có một số phân bổ (và deallocation, do finalizer dựa trên một) nhưng ByteArrayInputStream có cùng một chi phí phân bổ như ByteBuffer.wrap và như một tiền thưởng tất cả các phương pháp được đồng bộ, cộng với ByteBuffer có xu hướng thưởng thức thêm nội tại của JIT. Ngoài ra, bạn không tạo một ByteBuffer trực tiếp cho mỗi gói nhưng một lần trên mỗi socket (hoặc lấy nó ra khỏi một pool). – bestsss

3

Mã của bạn sẽ hiệu quả hơn nếu thay vì đọc gói vào mảng byte (sao chép dữ liệu từ bộ đệm gốc vào mảng) và sau đó gói nó vào ByteBuffer mới (tạo đối tượng mới) và chuyển đổi thành ShortBuffer (tạo một đối tượng mới), bạn chỉ thiết lập các đối tượng của mình một lần và tránh được bản sao.

Bạn có thể thực hiện điều này bằng cách sử dụng DatagramChannel.socket() để tạo ổ cắm, sau đó kết nối nó như bình thường và sử dụng socket.getChannel() để nhận đối tượng DatagramChannel.Đối tượng này sẽ cho phép bạn đọc các gói trực tiếp vào một ByteBuffer hiện có (mà bạn nên tạo với ByteBuffer.allocateDirect để đạt hiệu quả tối đa). Sau đó, bạn có thể sử dụng asShortBuffer() một lần để tạo một khung nhìn dữ liệu của bạn dưới dạng quần short và đọc từ ShortBuffer đó sau mỗi lần bạn nạp lại ByteBuffer.

Mã này do đó trông như thế này:

DatagramSocket socket = DatagramChannel.socket(); 
// code to connect socket 
DatagramChannel channel = socket.getChannel(); 
ByteBuffer buffer = ByteBuffer.allocateDirect (10000); 
// you may want to invoke buffer.order(...) here to tell it what byte order to use 
ShortBuffer shortBuf = buffer.asShortBuffer(); 

// in your receive loop: 
buffer.clear(); 
channel.receive(buffer); 
shortBuf.position(0).limit(buffer.position()/2); // may ignore a byte if odd number received 
shortBuf.get(soundBuf,0,shortBuf.limit()); 

Bạn nên tìm thấy điều này là nhiều hơn nữa hiệu quả hơn so với mã trước đó của bạn bởi vì nó tránh được toàn bộ một bản sao của dữ liệu và chuyển đổi định dạng được xử lý bởi tay mã được tối ưu hóa chứ không phải là trình biên dịch tạo ra thao tác byte có thể là tối ưu. Nó sẽ hiệu quả hơn nếu bạn sử dụng thứ tự byte nền tảng (tôi tin rằng Android sử dụng thứ tự byte nhỏ trên tất cả các nền tảng mà nó có sẵn và mã của bạn ở trên có vẻ là người lớn, vì vậy điều này có thể không thực hiện được cho bạn), trong trường hợp này shortBuf.get() trở thành một bản sao bộ nhớ trực tiếp.

+0

Câu trả lời hay nhất Jules, không chắc tại sao đây không phải là câu trả lời được chấp nhận. –

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