Cách dữ liệu được ghi vào một tệp thực sự được xóa/đồng bộ hóa với thiết bị khối bằng Java.Thực sự buộc đồng bộ/tuôn ra tệp trong Java
Tôi đã thử mã này với nio:.
FileOutputStream s = new FileOutputStream(filename)
Channel c = s.getChannel()
while(xyz)
c.write(buffer)
c.force(true)
s.getFD().sync()
c.close()
Tôi cho rằng c.force (true) togehter với s.getFD() sync() nên là đủ vì doc cho force bang
Buộc mọi bản cập nhật cho tệp của kênh này được ghi vào thiết bị lưu trữ chứa tệp đó. Nếu tệp của kênh này nằm trên thiết bị lưu trữ cục bộ thì khi phương thức này trả về, đảm bảo rằng tất cả thay đổi được thực hiện cho tệp kể từ khi kênh này được tạo hoặc kể từ khi phương thức này được gọi lần cuối, sẽ được ghi vào thiết bị đó. Điều này rất hữu ích để đảm bảo rằng thông tin quan trọng không bị mất trong trường hợp xảy ra sự cố hệ thống.
Các tài liệu để sync trạng thái:
Force tất cả các bộ đệm hệ thống để đồng bộ hóa với các thiết bị cơ bản. Phương thức này trả về sau khi tất cả các dữ liệu đã sửa đổi và các thuộc tính của FileDescriptor này đã được ghi vào (các) thiết bị liên quan. Đặc biệt, nếu FileDescriptor này đề cập đến một phương tiện lưu trữ vật lý, chẳng hạn như một tệp trong hệ thống tệp, đồng bộ sẽ không trả lại cho đến khi tất cả các bộ đệm được sửa đổi trong bộ đệm được liên kết với FileDesecriptor này đã được ghi vào phương tiện vật lý. đồng bộ hóa có nghĩa là được sử dụng bởi mã yêu cầu lưu trữ vật lý (chẳng hạn như tệp) ở trạng thái đã biết.
Hai cuộc gọi này là đủ. Là nó? Tôi đoán là không.
Nền: Tôi thực hiện so sánh hiệu suất nhỏ (2 GB, viết tuần tự) bằng C/Java và phiên bản Java nhanh gấp hai lần phiên bản C và có thể nhanh hơn phần cứng (120 MB/s trên một HD duy nhất). Tôi cũng đã thử thực hiện đồng bộ hóa công cụ dòng lệnh với Runtime.getRuntime(). Exec ("sync") nhưng điều đó đã không thay đổi hành vi.
Mã C kết quả là 70 MB/s được (sử dụng các API cấp thấp (mở, viết, đóng) không thay đổi nhiều):
FILE* fp = fopen(filename, "w");
while(xyz) {
fwrite(buffer, 1, BLOCK_SIZE, fp);
}
fflush(fp);
fclose(fp);
sync();
Nếu không có cuộc gọi cuối cùng để đồng bộ; Tôi nhận được các giá trị không thực tế (hơn 1 GB hay còn gọi là hiệu năng bộ nhớ chính).
Tại sao có sự khác biệt lớn giữa C và Java? Có hai possiblities: Tôi không đồng bộ dữ liệu một cách chính xác trong Java hoặc mã C là suboptimal vì một lý do nào đó.
Cập nhật: Tôi đã thực hiện strace chạy với "strace -cfT cmd". Dưới đây là kết quả:
C (Low-Level API): MB/s 67,389782
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 87.21 0.200012 200012 1 fdatasync 11.05 0.025345 1 32772 write 1.74 0.004000 4000 1 sync
C (High-Level API): MB/s 61,796458
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 73.19 0.144009 144009 1 sync 26.81 0.052739 1 65539 write
Java (1.6 SUN JRE, java.io API): MB/s 128.6755466197537
% time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 80.07 105.387609 3215 32776 write 2.58 3.390060 3201 1059 read 0.62 0.815251 815251 1 fsync
Java (1,6 SUN JRE, java.nio API): MB/s 127,45830221558376
5.52 0.980061 490031 2 fsync 1.60 0.284752 9 32774 write 0.00 0.000000 0 80 close
Thời gian giá trị dường như là hệ thống thời gian duy nhất và do đó là khá vô nghĩa.
Cập nhật 2: Tôi đã chuyển sang máy chủ khác, khởi động lại và tôi sử dụng ext3 được định dạng mới. Bây giờ tôi chỉ nhận được 4% sự khác biệt giữa Java và C. Tôi chỉ đơn giản là không biết những gì đã đi sai. Đôi khi mọi thứ thật kỳ lạ. Tôi nên thử đo bằng hệ thống khác trước khi viết câu hỏi này. Lấy làm tiếc.
Cập nhật 3: Để tóm tắt câu trả lời:.
- Sử dụng c.force (true) tiếp theo là s.getFD() sync() cho Java NIO và s.flush() và s.getFD() .sync() cho API luồng của Java. Đối với API cấp cao trong C, đừng quên đồng bộ hóa. Một fflush đã gửi dữ liệu đến hệ điều hành, nhưng không mang dữ liệu của bạn đến thiết bị khối.
- Sử dụng vạch để phân tích các syscalls được thực hiện bằng lệnh
- Cross kiểm tra kết quả của bạn trước khi đăng câu hỏi.
Cập nhật 4: Hãy lưu ý theo dõi sau question.
Tôi thực sự muốn xem thông lượng chỉ sử dụng các chức năng của phần 2. –
Bạn đang sử dụng gì cho BLOCK_SIZE? Nó có cùng kích thước với bộ đệm của bạn trong Java không? 512 sẽ rất tối ưu trong những ngày này. Bạn có thể muốn ít nhất 4096 (kích thước trang trên x86) hoặc có thể cao hơn. Tôi đã thấy những cải tiến có thể đo lường lên đến 32k trên một số máy. Oh, và tất nhiên nếu bộ đệm của bạn được liên kết trang, nó sẽ cung cấp cho hạt nhân nhiều chỗ hơn để tối ưu hóa. – aij
Một vấn đề khác có thể là mã bạn đã đăng không sử dụng "API cấp thấp (mở, viết, đóng)". Nó đang sử dụng cấp cao hơn, API stdio di động (fopen, fwrite, fclose) sẽ thêm một lớp đệm bổ sung theo mặc định. Bạn đã tắt một cách rõ ràng một nơi nào đó bên ngoài mã bạn đã đăng? – aij