Ho letto di recente che nei nuovi computer l'I/O di Java offre prestazioni migliori di NIO a causa della nuova disponibilità di macchine multi-core.I/O Java vs NIO: confronto benchmark rapido
Ho eseguito un test rapido confrontando il tempo di trasferimento di I/O e NIO sulla LAN utilizzando l'indirizzo di loopback localhost.
Nota: Questo è usare JDK 7
I risultati (3 prove):
I trasferimenti/O mediati 21789.3ms
trasferimenti NIO media 22771.0ms
Vale anche la pena notare che l'utilizzo della CPU è aumentato del 10% circa su ogni trasferimento NIO rispetto all'I/O.
La mia domanda per voi è se il mio codice di confronto è giusto? Ho scritto bene/uguale I/O e codice NIO? In caso contrario, come posso migliorare e rieseguire questo test?
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();
}
}
}
Informazione supplementare:
Windows Vista (SP2) su Dell Studio XPS 435MT
1 Gen i7 processore quad-core 2.67GHz
6GB di RAM
a 64-bit architettura
non sono convinto che la parte di analisi comparativa di questo è giusto - in Java, si ha realmente bisogno di fare le cose come scaldare la JVM e tutti. Potresti essere in grado di utilizzare uno strumento di benchmark come http://code.google.com/p/caliper/. –
@LouisWasserman Come suggeriresti di riscaldare la JVM e/o di migliorare questo codice? – bgroenks
Utilizza un framework di benchmark creato da persone che sanno cosa stanno facendo in JVM, in sostanza. Non scrivere il proprio codice di "sincronizzazione di un'operazione". Ci sono molti altri modi per sbagliare rispetto a quello che serve per farlo bene. –