Java I / O против NIO: быстрое сравнение производительности - PullRequest
7 голосов
/ 05 февраля 2012

Недавно я прочитал, что на новых компьютерах ввод-вывод Java работает лучше, чем NIO, благодаря новой доступности многоядерных машин.

Я провел быстрый тест, сравнивая время передачи ввода-вывода и NIO по локальной сети, используя адрес обратной связи localhost.

Примечание. Используется JDK 7

.

Результаты (3 испытания):

Передачи ввода / вывода в среднем 21789,3 мс

NIO переводы в среднем 22771.0ms

Стоит также отметить, что загрузка ЦП на каждой передаче NIO оказалась примерно на 10% выше по сравнению с вводом / выводом.

Мой вопрос к вам, является ли мой код сравнения справедливым? Я написал хороший / равный I / O и NIO код? Если нет, как я могу улучшить и повторно запустить этот тест?

    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();
        }
    }
}

Дополнительная информация:

Windows Vista (SP2) в Dell Studio XPS 435MT

1-й поколения i7 четырехъядерный процессор 2,67 ГГц

6 ГБ ОЗУ

64-битная архитектура

1 Ответ

4 голосов
/ 06 февраля 2012

Предложения

  • Попробуйте сравнить блокировку ввода-вывода с блокировкой ввода-вывода.Ваш код будет короче.Если вы собираетесь тестировать IO, используйте IO на клиенте и сервере.Если вы собираетесь использовать NIO, используйте одно и то же на обоих концах.
  • Используйте прямые байтовые буферы.
  • Не читайте и не записывайте файлы, так как они не являются частью теста и могутнамного медленнее.Просто передайте пустые блоки данных.
  • Попробуйте использовать блоки разных размеров, например, 8 КБ.
  • Рассмотрите тип данных, которыми вы хотите обмениваться.например, ByteBuffer может сделать чтение int и long более эффективным.
  • Сообщать числа в терминах пропускной способности.Я бы ожидал увидеть от 1 до 3 ГБ / с по обратной связи.

http://vanillajava.blogspot.com/2010/07/java-nio-is-faster-than-java-io-for.html

...