2011-01-18 51 views
8

Tôi hiện đang phát triển ứng dụng đồ họa 3D bằng cách sử dụng JOGL (liên kết Java OpenGL). Tóm lại, tôi có một tệp nhị phân phong cảnh khổng lồ. Do kích thước của nó, tôi phải truyền các khối địa hình trong thời gian chạy. Do đó, chúng tôi thấy rõ mối quan tâm truy cập ngẫu nhiên. Tôi đã hoàn thành việc thực hiện đầu tiên (và bẩn :)) (có lẽ nó là đa luồng), nơi tôi đang sử dụng một cách tiếp cận ngu ngốc ... Đây là khởi tạo của nó:Truyền tệp trong Java

dataInputStream = new DataInputStream(new BufferedInputStream(fileInputStream,4 * 1024); 
dataInputStream.mark(dataInputStream.available()); 

Và khi tôi cần phải đọc (stream) đoạn đặc biệt (tôi đã biết nó "bù đắp" trong tập tin) tôi đang thực hiện như sau (xấu hổ về tôi :)):

dataInputStream.reset(); 
dataInputStream.skipBytes(offset); 
dataInputStream.read(whatever I need...); 

Kể từ khi tôi đã có chút kinh nghiệm đó là người đầu tiên điều tôi có thể nghĩ đến :) Vì vậy, cho đến bây giờ tôi đã đọc 3 bài viết hữu ích và khá thú vị (tôi đề nghị bạn đọc chúng, có lẽ nếu bạn quan tâm đến chủ đề này)

  1. Byte Buffers and Non-Heap Memory - Ông Gregory có vẻ là biết chữ trong Java NIO.

  2. Java tip: Làm thế nào để đọc các tập tin một cách nhanh chóng [http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly] - Đó là một mốc thú vị.

  3. bài viết: Tuning Java I/O Hiệu suất [http://java.sun.com/developer/technicalArticles/Programming/PerfTuning/] - khuyến nghị đơn giản Sun, nhưng hãy cuộn xuống và có một cái nhìn tại " Truy cập ngẫu nhiên "ở đó; chúng cho thấy việc thực hiện đơn giản RandomAccessFile (RAF) với khả năng tự đệm.

Ông Gregory cung cấp một số tệp * .java ở cuối bài viết của mình. Một trong số đó là điểm chuẩn giữa FileChannel + ByteBuffer + Mapping (FBM) và RAF. Anh nói rằng anh nhận thấy tốc độ tăng gấp 4 lần khi sử dụng FBM so với RAF. Tôi đã chạy điểm chuẩn này trong các điều kiện sau:

  1. Khoản bù trừ (khoảng cách truy cập) được tạo ngẫu nhiên (trong phạm vi tệp, ví dụ: 0 - file.length());
  2. Kích thước tệp là 220MB;
  3. 1 000 000 truy cập (75% đọc và 25% viết)

Kết quả thật đáng kinh ngạc:

~ 28 giây cho RAF! ~ 0,2 giây đối với FBM!

Tuy nhiên, việc triển khai RAF trong điểm chuẩn này không tự đệm (bài viết thứ 3 nói về một), vì vậy tôi đoán đó là phương thức "RandomAccessFile.seek".

Ok, bây giờ sau khi tất cả những điều tôi đã học được có 1 câu hỏi và 1 tiến thoái lưỡng nan :)

Câu hỏi: Khi chúng tôi đang lập bản đồ một tập tin sử dụng "FileChannel.map" không Java sao chép toàn bộ tập tin nội dung vào MappedByteBuffer? Hay nó chỉ mô phỏng nó?Nếu nó sao chép, sau đó sử dụng cách tiếp cận FBM là không thích hợp cho tình hình của tôi, phải không?

Dilemma: Phụ thuộc vào câu trả lời của bạn về vấn đề ...

  1. Nếu bản đồ sao chép một tập tin, sau đó nó có vẻ như tôi chỉ có 2 giải pháp khả thi để đi: RAF + tự đệm (một từ bài viết thứ 3) hoặc sử dụng vị trí trong FileChannel (không có ánh xạ) ... Cái nào sẽ tốt hơn?

  2. Nếu ánh xạ không sao chép tệp, thì tôi có 3 tùy chọn: hai tùy chọn trước đó và FBM chính nó.

Chỉnh sửa: Đây là một câu hỏi nữa. Một số bạn ở đây nói rằng ánh xạ không sao chép tệp vào MappedByteBuffer. Ok sau đó, tại sao tôi không thể ánh xạ 1GB tệp sau đó, tôi nhận được thông báo "không thể lập bản đồ" ...

PS Tôi muốn nhận được câu trả lời hoàn chỉnh với lời khuyên, vì tôi không thể để tìm thông tin nhất quán về chủ đề này trên internet.

Cảm ơn :)

Trả lời

3

Không, dữ liệu không được đệm. Một MappedByteBuffer tham chiếu đến dữ liệu bằng cách sử dụng pointer. Nói cách khác, dữ liệu không được sao chép, nó chỉ đơn giản là ánh xạ vào bộ nhớ vật lý. Xem API docs nếu bạn chưa có.

Một tập tin bộ nhớ ánh xạ là một phân đoạn của bộ nhớ ảo mà đã được gán một trực tiếp byte-cho-byte tương quan với một số phần của một tập tin hoặc nguồn tập tin như thế nào. Tài nguyên này là thường là tệp có nội dung hiện diện trên đĩa, nhưng cũng có thể là thiết bị , đối tượng bộ nhớ dùng chung hoặc các tài nguyên khác mà hệ điều hành có thể tham chiếu thông qua bộ mô tả tệp. Khi có mặt, mối tương quan giữa tệp và không gian bộ nhớ cho phép ứng dụng để xử lý ánh xạ phần như thể đó là bộ nhớ chính.

Nguồn: Wikipedia

Nếu bạn đang đi để được đọc dữ liệu khá thường xuyên, nó là một ý tưởng tốt để ít nhất bộ nhớ cache một số của nó.

+0

Nếu bạn nói rằng MappedByteBuffer là một con trỏ đến HD, thì làm thế nào nó đạt được kết quả tốt như vậy trong điểm chuẩn? Tính năng tăng tốc duy nhất có thể có trong IO mà cá nhân tôi biết là TRUY CẬP TRUY CẬP DISK NHƯNG CÓ THỂ KHẢ NĂNG và giải pháp duy nhất ở đây là đệm. Một lần nữa, nếu bạn biết chữ đầy đủ về mối quan tâm này, vui lòng chi tiết hơn. –

+0

@Haroogan Tôi trích dẫn từ bài viết đó: "sự khác biệt gần như hoàn toàn do các công tắc ngữ cảnh hạt nhân" – someguy

+0

Bạn phải nói đùa bằng cách giới thiệu tôi với javadoc, phải không? Coz, không có thông tin cụ thể mà tôi yêu cầu. Tôi vẫn chưa có bất kỳ câu trả lời trực tiếp hoặc ý tưởng thích hợp và ý kiến ​​về các giải pháp có thể. –

2

Đối với tệp 220 MB, tôi sẽ nhớ ánh xạ toàn bộ nội dung vào bộ nhớ ảo. Lý do FBM là quá nhanh là nó không thực sự đọc dữ liệu vào bộ nhớ, nó chỉ làm cho nó có sẵn.

Lưu ý: khi bạn chạy thử nghiệm bạn cần so sánh như ví dụ: khi tệp nằm trong bộ nhớ cache của hệ điều hành, nó sẽ nhanh hơn nhiều bất kể bạn làm như thế nào. Bạn cần phải lặp lại phép thử nhiều lần để có được kết quả tái tạo.

+0

Bạn có ý nghĩa gì khi "khả dụng"? Có thể chỉ có 2 tùy chọn: tệp được sao chép hoàn toàn vào MappedByteBuffer (kích thước tối đa là 2GB cho hệ thống 32 bit) hoặc MappedByteBuffer chỉ mô phỏng tệp này bằng cách sử dụng tính năng đệm nền, dự đoán logic hoặc bất cứ điều gì ... Vì tôi đã cố gắng ánh xạ 1GB tập tin và nó không làm như vậy, tôi phải kết luận rằng bản đồ của nó dường như sao chép toàn bộ tập tin để MappedByteBuffer ... hoặc tôi vẫn còn sai? Vui lòng chi tiết hơn trong câu trả lời của bạn. –

+0

Khi ánh xạ, hệ điều hành ánh xạ tệp vào bộ nhớ ảo. Các trang (thường 4KB) của tập tin được đưa vào bộ nhớ khi bạn đọc/ghi chúng và được tuôn ra trở lại đĩa chậm. (Hoặc khi bạn buộc một tuôn ra) Không có cách nào bạn có thể đọc một tập tin 220 MB vào bộ nhớ trong 0,2 giây. Tôi không chắc tại sao một tệp 1 GB không thể được ánh xạ trừ khi bạn đang sử dụng một JVM 32 bit. –

+0

Vâng, tôi đang sử dụng JVM 32 bit, do đó tôi không hiểu tại sao ánh xạ tệp 1GB không thành công ... bất kỳ ý tưởng nào? Hiện tại tôi chỉ quan tâm đến việc đọc, vì vậy tôi không cần tuôn ra và vv Bạn chỉ nói rằng hệ điều hành đang tải các trang 4KB vào bộ nhớ ảo, nhưng bạn thấy đó là những gì tôi đã nói trước đây, i. e. MappedByteBuffer chỉ mô phỏng tệp này bằng cách sử dụng logic đệm nền chậm mà tôi không thể kiểm soát. Đúng? –

1

Bạn có nhận thấy rằng nếu bạn chạy một chương trình, sau đó đóng chương trình, sau đó chạy lại chương trình, nó sẽ khởi động nhanh hơn nhiều lần thứ hai?Điều này xảy ra bởi vì hệ điều hành đã lưu trữ các phần của các tệp được truy cập trong lần chạy đầu tiên và không cần truy cập vào đĩa cho chúng. Bộ nhớ ánh xạ một tập tin về cơ bản cho phép một chương trình truy cập vào các bộ đệm, do đó giảm thiểu các bản sao được thực hiện khi đọc nó. Lưu ý rằng bộ nhớ ánh xạ một tập tin không làm cho nó được đọc toàn bộ vào bộ nhớ; các bit và phần mà bạn đọc được đọc từ đĩa theo yêu cầu. Nếu hệ điều hành xác định rằng có bộ nhớ thấp, nó có thể quyết định giải phóng một số phần của tệp được ánh xạ khỏi bộ nhớ và để chúng trên đĩa.

Chỉnh sửa: Nội dung bạn muốn là FileInputStream.getChannel(). Map(), sau đó điều chỉnh nó thành InputStream, sau đó kết nối nó với DataInputStream.

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