Recientemente leí que en las computadoras más nuevas la E/S de Java funciona mejor que NIO debido a la nueva disponibilidad de las máquinas de varios núcleos.Java I/O vs NIO: Comparación rápida de puntos de referencia
Realicé una prueba rápida comparando el tiempo de transferencia de E/S y NIO en la LAN utilizando la dirección de bucle localhost.
Nota: Este es el uso de JDK 7
Los resultados (3 ensayos):
I/O transferencias promediaron 21789.3ms
transferencias NIO promediaron 22771.0ms
También vale la pena señalar que el uso de la CPU parece ser un 10% mayor en cada transferencia de NIO en comparación con la E/S.
Mi pregunta es si mi código de comparación es justo. ¿Escribí E/S buena/igual y el código NIO? Si no, ¿cómo puedo mejorar y volver a ejecutar esta prueba?
public static void main(String[] args) {
System.out.println("Initiating test sequence...");
new Thread(new Client()).start();
try {
System.out.println("Server I/O initiating...");
ServerSocket server = new ServerSocket(5555);
Socket sock = server.accept();
System.out.println("Server connected to client successfully");
InputStream is = sock.getInputStream();
File output = new File("C:/test_root/video.avi");
FileOutputStream fos = new FileOutputStream(output);
byte[] data = new byte[1024];
int len=0;
System.out.println("Server initiating transfer - Timer starting");
long start = System.currentTimeMillis();
while((len=is.read(data))>0) {
fos.write(data, 0, len);
fos.flush();
}
fos.close();
is.close();
sock.close();
server.close();
long end = System.currentTimeMillis();
System.out.println("Network I/O transfer time = "+(end-start)+"ms");
System.out.println("Server NIO initiating...");
ServerSocketChannel serverChan = ServerSocketChannel.open();
serverChan.bind(new InetSocketAddress(5555));
SocketChannel chan = serverChan.accept();
chan.configureBlocking(false);
System.out.println("Server channel connected");
FileChannel fc = (FileChannel) Files.newByteChannel(Paths.get("C:/test_root/video.avi"), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
ByteBuffer buff = ByteBuffer.allocate(1024);
System.out.println("Server initiating transfer - Timer starting");
start = System.currentTimeMillis();
while(chan.read(buff)>=0 || buff.position() > 0) {
buff.flip();
fc.write(buff);
buff.compact();
}
chan.close();
fc.close();
serverChan.close();
end = System.currentTimeMillis();
System.out.println("Network NIO transfer time = "+(end-start)+"ms");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Test completed!");
}
static class Client implements Runnable {
public void run() {
try {
System.out.println("Client I/O initiating...");
Socket sock = new Socket("localhost", 5555);
System.out.println("Client connected to server successfully!");
OutputStream os = sock.getOutputStream();
File input = new File(System.getProperty("user.home")+"/Documents/clip0025.avi");
FileInputStream fis = new FileInputStream(input);
byte[] data = new byte[1024];
int len=0;
int tot=0;
int perc=0;
while((len=fis.read(data))>0) {
os.write(data, 0, len);
os.flush();
tot+=len;
int prev = perc;
perc = getPercentage(tot, input.length());
if(perc !=prev && (perc == 10 || perc == 25 || perc == 50 || perc == 75 || perc == 98))
System.out.println("Client reporting: "+perc+"% read");
}
os.close();
fis.close();
sock.close();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Client NIO initiating...");
SocketChannel sc = SocketChannel.open();
boolean connected = sc.connect(new InetSocketAddress("localhost",5555));
if(!connected)
connected = sc.finishConnect();
if(!connected)
throw(new IOException("Client failed to connect"));
System.out.println("Client channel connected");
sc.configureBlocking(false);
FileChannel fc = (FileChannel) Files.newByteChannel(input.toPath(), StandardOpenOption.READ);
ByteBuffer buff = ByteBuffer.allocate(1024);
len=0;
tot=0;
while((len=fc.read(buff))>=0||buff.position()>0) {
buff.flip();
sc.write(buff);
buff.compact();
tot+=len;
int prev = perc;
perc = getPercentage(tot, input.length());
if(perc !=prev && (perc == 10 || perc == 25 || perc == 50 || perc == 75 || perc == 98))
System.out.println("Client reporting: "+perc+"% read");
}
sc.close();
fc.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Información adicional:
Windows Vista (SP2) en Dell Studio XPS 435mt
primera procesador de cuatro núcleos generación i7 2.67GHz
6 GB de RAM
de 64 bits arquitectura
no estoy convencido de que la parte de la evaluación comparativa de esto es justo - en Java, que realmente tiene que hacer cosas como calentar el JVM y todo. Es posible que pueda utilizar una herramienta de evaluación comparativa como http://code.google.com/p/caliper/. –
@LouisWasserman ¿Cómo sugeriría calentar la JVM y/o mejorar este código? – bgroenks
Utilice un marco de evaluación comparativa creado por personas que saben lo que están haciendo con la JVM, en esencia. No escriba su propio código "cronometrando una operación". Hay muchas más maneras de equivocarse que de hacerlo bien. –