gpt4 book ai didi

Java 文件 IO 因大量连续写入而变慢

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:42:59 24 4
gpt4 key购买 nike

我编写了一个驱动器删除程序,旨在安全地覆盖驱动器的可用空间。一开始一切都很好,然后随着时间的推移,速度急剧下降。我有一个 1TB 的驱动器,开始速度大约为 120MB/s,然后慢慢下降到 70。起初我以为是驱动器问题,所以我在我的 RAID0 velociraptor 驱动器上测试了它,它达到了 160MB/s 将近半分钟,然后慢慢地下降到 110 左右。这似乎不仅仅是缓存填满,因为它需要一分钟左右的时间才能完全减速。

首先,我向磁盘写入数据的方式可能存在问题,还是其他语言的 HDD 实际上也能正常运行?

其次,我是否会看到与速度相关的切换到 NIO 的任何潜在好处?使用 ISAAC 删除是多线程的,所以瓶颈实际上只是看起来的写入速度。

最后,也许它在我的速度计算中。但我把它留得非常简单,所以我不明白这是怎么回事。

编辑:(一些信息)

Both are regular magnetic drives. The 1TB drive is a WD 7200rpm. The raid0 setup is two WD 10,000rpm. Running Windows 7 Ultimate.

java version "1.8.0_45". Java(TM) SE Runtime Environment (build 1.8.0_45-b15). Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode).

您可以测试这个运行示例:(cleaner.DriveCleaner)

package cleaner;

import java.awt.EventQueue;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.SecureRandom;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JProgressBar;
import javax.swing.text.NumberFormatter;

/**
* @author Colby
*/
public class DriveCleaner extends javax.swing.JFrame {

public DriveCleaner() {
initComponents();
refreshDrives();
}

protected static boolean running = false;
private Thread worker;

private void refreshDrives() {
File[] roots = File.listRoots();
drives.setModel(new DefaultComboBoxModel(roots));
}

@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {

buttonGroup1 = new javax.swing.ButtonGroup();
jLabel1 = new javax.swing.JLabel();
jSeparator1 = new javax.swing.JSeparator();
drives = new javax.swing.JComboBox();
normSelect = new javax.swing.JRadioButton();
randSelect = new javax.swing.JRadioButton();
jLabel2 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
passes = new javax.swing.JComboBox();
jLabel4 = new javax.swing.JLabel();
runButton = new javax.swing.JButton();
jSeparator2 = new javax.swing.JSeparator();
jSeparator3 = new javax.swing.JSeparator();
progress = new javax.swing.JProgressBar();
jMenuBar1 = new javax.swing.JMenuBar();
jMenu1 = new javax.swing.JMenu();
jMenuItem1 = new javax.swing.JMenuItem();

setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("DriveCleaner V1.0");

jLabel1.setFont(new java.awt.Font("Consolas", 2, 17)); // NOI18N
jLabel1.setText("DriveCleaner");

buttonGroup1.add(normSelect);
normSelect.setText("Simple Clean");
normSelect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
normSelectActionPerformed(evt);
}
});

buttonGroup1.add(randSelect);
randSelect.setSelected(true);
randSelect.setText("ISAAC 256 Clean");
randSelect.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
randSelectActionPerformed(evt);
}
});

jLabel2.setText("Drive:");

jLabel3.setText("Passes:");

passes.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "1", "2", "4", "8", "16", "32", "64", "128" }));
passes.setSelectedIndex(2);

jLabel4.setText("Method:");

runButton.setText("Clean");
runButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
runButtonActionPerformed(evt);
}
});

jSeparator2.setOrientation(javax.swing.SwingConstants.VERTICAL);

progress.setString("");
progress.setStringPainted(true);

jMenu1.setText("File");

jMenuItem1.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F5, 0));
jMenuItem1.setText("Refresh Drives");
jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jMenuItem1ActionPerformed(evt);
}
});
jMenu1.add(jMenuItem1);

jMenuBar1.add(jMenu1);

setJMenuBar(jMenuBar1);

javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jSeparator3)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(drives, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel2))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(passes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel3))
.addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(randSelect)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(normSelect))
.addComponent(jLabel4))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 31, Short.MAX_VALUE)
.addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 12, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(runButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(progress, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2)
.addComponent(jLabel3)
.addComponent(jLabel4))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(drives, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(passes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(randSelect)
.addComponent(normSelect)))
.addComponent(jSeparator2)
.addComponent(runButton, javax.swing.GroupLayout.DEFAULT_SIZE, 43, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);

pack();
}// </editor-fold>

private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {

if (running) {

runButton.setText("Halting");
runButton.setEnabled(false);

new Thread() {

@Override
public void run() {
try {
running = false;
worker.join();

} catch (InterruptedException e) {
throw new RuntimeException(e);
}
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {
progress.setString("");
progress.setValue(0);

runButton.setEnabled(true);
runButton.setText("Clean");
}
});
}
}.start();

} else {
running = true;
runButton.setText("Stop");
worker = new Thread(new Runnable() {

@Override
public void run() {

try {
Wipe.wipe(progress, (File) drives.getSelectedItem(), Integer.parseInt((String) passes.getSelectedItem()), useRandomData);

} catch (Exception e) {
e.printStackTrace();
}
}
});
worker.start();
}
}

private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {
refreshDrives();
}

private void randSelectActionPerformed(java.awt.event.ActionEvent evt) {
useRandomData = true;
}

private void normSelectActionPerformed(java.awt.event.ActionEvent evt) {
useRandomData = false;
}

protected static boolean useRandomData = true;

public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(DriveCleaner.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(DriveCleaner.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(DriveCleaner.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(DriveCleaner.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>

/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new DriveCleaner().setVisible(true);
}
});
}

// Variables declaration - do not modify
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JComboBox drives;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JLabel jLabel3;
private javax.swing.JLabel jLabel4;
private javax.swing.JMenu jMenu1;
private javax.swing.JMenuBar jMenuBar1;
private javax.swing.JMenuItem jMenuItem1;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JSeparator jSeparator2;
private javax.swing.JSeparator jSeparator3;
private javax.swing.JRadioButton normSelect;
private javax.swing.JComboBox passes;
private javax.swing.JProgressBar progress;
private javax.swing.JRadioButton randSelect;
private javax.swing.JButton runButton;
// End of variables declaration
}

class ISAAC {

public ISAAC(int ai[]) {
cryptArray = new int[256];
keySetArray = new int[256];
System.arraycopy(ai, 0, keySetArray, 0, ai.length);

initializeKeySet();
}

public int getNextKey() {
if (keyArrayIdx-- == 0) {
generateNextKeySet();
keyArrayIdx = 255;
}
return keySetArray[keyArrayIdx];
}

public void generateNextKeySet() {
cryptVar2 += ++cryptVar3;
for (int i = 0; i < 256; i++) {
int j = cryptArray[i];
if ((i & 3) == 0) {
cryptVar1 ^= cryptVar1 << 13;
} else if ((i & 3) == 1) {
cryptVar1 ^= cryptVar1 >>> 6;
} else if ((i & 3) == 2) {
cryptVar1 ^= cryptVar1 << 2;
} else if ((i & 3) == 3) {
cryptVar1 ^= cryptVar1 >>> 16;
}
cryptVar1 += cryptArray[i + 128 & 0xff];
int k;
cryptArray[i] = k = cryptArray[(j & 0x3fc) >> 2] + cryptVar1 + cryptVar2;
keySetArray[i] = cryptVar2 = cryptArray[(k >> 8 & 0x3fc) >> 2] + j;
}
}

public void initializeKeySet() {
int i1;
int j1;
int k1;
int l1;
int i2;
int j2;
int k2;
int l = i1 = j1 = k1 = l1 = i2 = j2 = k2 = 0x9e3779b9;
for (int i = 0; i < 4; i++) {
l ^= i1 << 11;
k1 += l;
i1 += j1;
i1 ^= j1 >>> 2;
l1 += i1;
j1 += k1;
j1 ^= k1 << 8;
i2 += j1;
k1 += l1;
k1 ^= l1 >>> 16;
j2 += k1;
l1 += i2;
l1 ^= i2 << 10;
k2 += l1;
i2 += j2;
i2 ^= j2 >>> 4;
l += i2;
j2 += k2;
j2 ^= k2 << 8;
i1 += j2;
k2 += l;
k2 ^= l >>> 9;
j1 += k2;
l += i1;
}

for (int j = 0; j < 256; j += 8) {
l += keySetArray[j];
i1 += keySetArray[j + 1];
j1 += keySetArray[j + 2];
k1 += keySetArray[j + 3];
l1 += keySetArray[j + 4];
i2 += keySetArray[j + 5];
j2 += keySetArray[j + 6];
k2 += keySetArray[j + 7];
l ^= i1 << 11;
k1 += l;
i1 += j1;
i1 ^= j1 >>> 2;
l1 += i1;
j1 += k1;
j1 ^= k1 << 8;
i2 += j1;
k1 += l1;
k1 ^= l1 >>> 16;
j2 += k1;
l1 += i2;
l1 ^= i2 << 10;
k2 += l1;
i2 += j2;
i2 ^= j2 >>> 4;
l += i2;
j2 += k2;
j2 ^= k2 << 8;
i1 += j2;
k2 += l;
k2 ^= l >>> 9;
j1 += k2;
l += i1;
cryptArray[j] = l;
cryptArray[j + 1] = i1;
cryptArray[j + 2] = j1;
cryptArray[j + 3] = k1;
cryptArray[j + 4] = l1;
cryptArray[j + 5] = i2;
cryptArray[j + 6] = j2;
cryptArray[j + 7] = k2;
}

for (int k = 0; k < 256; k += 8) {
l += cryptArray[k];
i1 += cryptArray[k + 1];
j1 += cryptArray[k + 2];
k1 += cryptArray[k + 3];
l1 += cryptArray[k + 4];
i2 += cryptArray[k + 5];
j2 += cryptArray[k + 6];
k2 += cryptArray[k + 7];
l ^= i1 << 11;
k1 += l;
i1 += j1;
i1 ^= j1 >>> 2;
l1 += i1;
j1 += k1;
j1 ^= k1 << 8;
i2 += j1;
k1 += l1;
k1 ^= l1 >>> 16;
j2 += k1;
l1 += i2;
l1 ^= i2 << 10;
k2 += l1;
i2 += j2;
i2 ^= j2 >>> 4;
l += i2;
j2 += k2;
j2 ^= k2 << 8;
i1 += j2;
k2 += l;
k2 ^= l >>> 9;
j1 += k2;
l += i1;
cryptArray[k] = l;
cryptArray[k + 1] = i1;
cryptArray[k + 2] = j1;
cryptArray[k + 3] = k1;
cryptArray[k + 4] = l1;
cryptArray[k + 5] = i2;
cryptArray[k + 6] = j2;
cryptArray[k + 7] = k2;
}

generateNextKeySet();
keyArrayIdx = 256;
}
public int keyArrayIdx;
public int keySetArray[];
public int cryptArray[];
public int cryptVar1;
public int cryptVar2;
public int cryptVar3;
}

class Wipe {

private static BlockingQueue<byte[]> buffers, randata;

private static class SecureDataCreator implements Runnable {

@Override
public void run() {
try {
SecureRandom seeder = new SecureRandom();
ISAAC rand = new ISAAC(new int[]{seeder.nextInt(), seeder.nextInt(), seeder.nextInt(), seeder.nextInt()});
do {
byte[] next = buffers.take();
for (int i = 0; i < next.length; i++) {
next[i] = (byte) rand.getNextKey();
}
randata.add(next);

} while (true);

} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public static void wipe(JProgressBar prog, File drive, int numPasses, boolean random) throws IOException, InterruptedException, ParseException {

NumberFormat format = NumberFormat.getPercentInstance();
format.setMinimumFractionDigits(2);
NumberFormatter formatter = new NumberFormatter(format);

prog.setValue(0);
prog.setString("Opening file handle");

File wipeFile = new File(drive, "wipefile.dat");
wipeFile.deleteOnExit();

try (RandomAccessFile raf = new RandomAccessFile(wipeFile, "rw")) {

try {
while (wipeFile.getFreeSpace() > raf.length()) {
try {
raf.setLength(drive.getFreeSpace());

} catch (IOException e) {
raf.setLength(0);
}
}

int dataSize = 1024 * 1024 * 32;
int numCores = Runtime.getRuntime().availableProcessors();

boolean needWorkers = buffers == null && random;

if (needWorkers) {
for (int i = 0; i < numCores; i++) {
Thread worker = new Thread(new SecureDataCreator());
worker.setPriority(Thread.MIN_PRIORITY);
worker.start();
}

buffers = new ArrayBlockingQueue<>(numCores + 1);
randata = new ArrayBlockingQueue<>(numCores + 1);

for (int i = 0; i < numCores + 1; i++) {
buffers.add(new byte[dataSize]);
}
}

long startTime = System.nanoTime();
byte[] data = random ? null : new byte[dataSize];
for (int pass = 0; DriveCleaner.running && (pass < numPasses); pass++) {
raf.seek(0);

do {
long writeLen = dataSize;
if (raf.getFilePointer() + writeLen > raf.length()) {
writeLen = raf.length() - raf.getFilePointer();
}

if (random) {
data = randata.take();
}
raf.write(data, 0, (int) writeLen);
if (random) {
buffers.add(data);
}

double total = numPasses * raf.length();
double done = (pass * (raf.length() - 1)) + raf.getFilePointer();
float percent = (float) (done / total);

double elapsed = (System.nanoTime() - startTime) / (1000000D * 1000D);
float bytesPerSec = (float) (done / elapsed) / (1024F * 1024F);

prog.setValue((int) percent);
prog.setString("Cleaning " + drive + ". Pass #" + pass + "/" + numPasses + ". "
+ formatter.valueToString(new Float(percent))
+ " @" + (int) bytesPerSec + "mBps");

} while (raf.getFilePointer() < raf.length() && DriveCleaner.running);
prog.setString("Complete.");
}
System.out.println("done");

} finally {
raf.setLength(0);
}

} finally {
wipeFile.delete();
}
}
}

最佳答案

我有一些建议来隔离问题的根源,因为目前还没有任何迹象表明它是由 JVM、操作系统还是硬件引起的:

  • 您的随机数生成器可能已耗尽熵。作为测试,使用零而不是随机调用。
  • 衡量 JVM garbage collection times .许多临时数组对象的构造可能导致 GC 暂停。
  • 尝试在 Linux 上运行您的 Java 程序(例如,从可启动的 USB 或 CD),看看是否会出现同样的问题。
  • 尝试不同的 JVM 实现(例如 OpenJDK 与 Oracle JDK),看看是否会出现同样的问题。

关于Java 文件 IO 因大量连续写入而变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31062719/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com