2013-08-13 31 views
11

BỐI CẢNHSử dụng sun.misc.Unsafe, cách nhanh nhất để quét byte từ ByteBuffer trực tiếp là gì?

Giả sử tôi có một ByteBuffer trực tiếp:

ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); 

và giả sử tôi đi qua bộ đệm để một AsynchronousSocketChannel để đọc khối dữ liệu ra rằng ổ cắm lên đến X byte tại một thời điểm (1024 trong ví dụ ở đây).

Thời gian chuyển khỏi ổ cắm vào trực tiếp ByteBuffer thật tuyệt vời vì tất cả xảy ra trong không gian bộ nhớ hệ điều hành gốc; Tôi đã không đi qua JVM "máu-não" rào cản chưa ...

HỎI

Giả sử công việc của tôi là để quét qua tất cả các byte đọc lại từ bộ đệm byte trực tiếp, những gì là cách nhanh nhất để tôi có thể thực hiện việc này?

Ban đầu tôi đã yêu cầu "... sử dụng sun.misc.Unsafe" nhưng có thể đó là giả định không đúng.

CÓ THỂ PHƯƠNG PHÁP TIẾP CẬN

Tôi hiện thấy ba cách tiếp cận và người tôi tò mò nhất về là # 3:

  1. (DEFAULT) Sử dụng ByteBuffer của bulk-get để kéo byte trực tiếp từ vũ trụ OS mẹ đẻ vào cấu trúc byte nội bộ [1024].
  2. (UNSAFE) Sử dụng Unsafe's getByte ops để kéo các giá trị trực tiếp ra khỏi ByteBuffer bỏ qua tất cả việc kiểm tra giới hạn các tiêu chuẩn của ByteBuffer. Câu trả lời của Peter Lawrey here dường như gợi ý rằng những phương pháp gốc thô trong Unsafe thậm chí có thể được tối ưu hóa bởi trình biên dịch JIT ("nội tại") để hướng dẫn máy đơn dẫn đến thời gian truy cập tuyệt vời hơn nữa. (=== CẬP NHẬT === thú vị, có vẻ như lớp cơ bản DirectByteBuffer thực hiện chính xác điều này với get/put ops cho những người quan tâm.)
  3. (BANANAS) Trong một số loại tội phạm chống nhân loại, sử dụng Không an toàn, Tôi có thể copy the memory region của ByteBuffer trực tiếp đến cùng một địa chỉ bộ nhớ byte của tôi [1024] tồn tại ở bên trong máy ảo và chỉ bắt đầu truy cập mảng bằng cách sử dụng các chỉ mục int chuẩn không? (Điều này làm cho các giả định rằng "CopyMemory" hoạt động có khả năng có thể làm điều gì đó rất tuyệt vời được tối ưu hóa ở cấp hệ điều hành.

Nó xảy ra với tôi rằng giả định CopyMemory hoạt động thực hiện chính xác những gì nó quảng cáo, thậm chí trong nhiều không gian hệ điều hành tối ưu, rằng cách tiếp cận # 2 ở trên có lẽ vẫn là tối ưu nhất kể từ khi tôi không tạo bản sao của bộ đệm trước khi bắt đầu xử lý bộ đệm đó trước khi bắt đầu xử lý bộ đệm đó trước khi bắt đầu xử lý nó. lập kế hoạch kéo các byte vào một byte [] nội bộ nếu nó không cần thiết.

Cảm ơn bạn đã dành thời gian; chỉ tò mò nếu có ai (Peter?) đã nhận hạt với Unsafe để làm một cái gì đó như thế này.

Trả lời

1

ByteBuffer phương pháp cực kỳ nhanh, bởi vì các phương pháp này là nội tại, VM đã ánh xạ chúng tới các hướng dẫn cấp rất thấp. So sánh hai phương pháp này:

byte[] bytes = new byte[N]; 
    for(int m=0; m<M; m++) 
     for(int i=0; i<bytes.length; i++) 
      sum += bytes[i]; 

    ByteBuffer bb = ByteBuffer.allocateDirect(N); 
    for(int m=0; m<M; m++) 
     for(int i=0; i<bb.remaining(); i++) 
      sum += bb.get(i); 

trên máy của tôi, chênh lệch là 0,67ns so với 0,81ns (mỗi vòng lặp).

Tôi hơi ngạc nhiên khi ByteBuffer không nhanh bằng byte []. Nhưng tôi nghĩ bạn chắc chắn KHÔNG nên sao chép nó vào một byte [] sau đó truy cập.

+0

Không biết về thuộc tính "nội tại" của các phương thức ByteBuffer; bạn có nghĩa là phương pháp 'bản địa' trong lớp DirectBuffer cụ thể không? Trong trường hợp đó, điều đó sẽ làm chính xác những gì # 2 sẽ làm trong bài viết của tôi ở trên để đó là tin tuyệt vời. –

+0

@RiyadKalla nội tại! = Gốc. Các phương thức nội tại được "mã hóa cứng" trong JVM. – assylias

+0

@assylias Tôi hiểu; Tôi đã (không chính xác) đề cập đến những gì tôi đã tìm ra là các phương thức 'nguyên gốc' trên lớp impl DirectByteBuffer (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java /nio/DirectByteBuffer.java) nhưng bây giờ mà tôi nhìn vào nó, tôi thấy rằng không có phương pháp 'bản địa', nó chỉ đơn giản là thúc đẩy Unsafe để làm những ops. Tôi mispoke, cảm ơn bạn đã nắm bắt. –

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