Java IO против NIO, в чем разница?

Я очень люблю Java NIO, и я действительно хочу применить Java NIO к моей текущей системе, но когда я создал эти примеры приложений для сравнения между Java IO и NIO, это меня очень разочаровало.

вот мои 2 образца (я не помещаю весь исходный код)

Java IO

public class BlockingServerClient {

    private static final Logger log = Logger.getLogger(BlockingServerClient.class.getName());

    static final ExecutorService service = Executors.newCachedThreadPool();

    public static void main(String[] args) throws InterruptedException {
        int port = Integer.parseInt(args[0]);

        BlockingServerClient server = new BlockingServerClient();

        Server sr = server.new Server(port);
        service.submit(sr);
    }

    private class Server implements Runnable {

        .....

        public void run() {
            ServerSocket ss = null;
            try {
                ss = new ServerSocket(localPort);
                log.info("Server socket bound to " + localPort);

                while (true) {
                    Socket client = ss.accept();
                    log.info("Accepted connection from " + client.getRemoteSocketAddress());

                    service.submit(new SocketClient(client));
                }

            } catch (IOException e) {
                log.log(Level.SEVERE, "Server error", e);
            } finally {
                .....
            }
        }
    }

    private class SocketClient implements Runnable {

        .....

        public void run() {
            InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress();
            socketInfo = String.format("%s:%s", addr.getHostName(), addr.getPort());

            log.info("Start reading data from " + socketInfo);
            try {
                in = new BufferedReader(
                        new InputStreamReader(socket.getInputStream()));

                String input;
                while ((input = in.readLine()) != null) {
                    log.info(String.format("[%s] %s", socketInfo, input));

                    log.info("Socket " + socketInfo + " thread sleep 4s");
                    TimeUnit.SECONDS.sleep(4);
                }

            } catch (Exception ex) {
                log.log(Level.SEVERE, "Socket error", ex);
            } finally {
                .....
            }
        }
    }   
}

Java NIO

public class NonBlockingServerClient {

    private static final Logger log = Logger.getLogger(NonBlockingServerClient.class.getName());

    public static void main(String[] args) {
        int port = Integer.parseInt(args[0]);

        EventLoopGroup boss = new NioEventLoopGroup();
        EventLoopGroup worker = new NioEventLoopGroup();

        try {
            NonBlockingServerClient sc = new NonBlockingServerClient();

            Server server = sc.new Server(port, boss, worker);

            server.run();

        } catch (Exception e) {
            log.log(Level.SEVERE, "Error", e);
        } finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

    private class Server {

        .....

        public void run() {
            log.info("Start Server bootstrap");
            ServerBootstrap b = new ServerBootstrap();
            b.group(boss, worker)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<Channel>() {

                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ChannelPipeline pipe = ch.pipeline();
                    pipe.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
                    pipe.addLast(new StringDecoder());
                    pipe.addLast(new ClientHandler());
                }
            });

            ChannelFuture future = null;
            try {
                future = b.bind(port).sync();
                future.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                log.log(Level.SEVERE, "Server binding error", e);
                future.channel().close();
            }

        }
    }

    private class ClientHandler extends SimpleChannelInboundHandler<String> {

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, String msg)
                throws Exception {
            log.info(String.format("[%s] %s", ctx.channel().remoteAddress(), msg));
            log.info(ctx.channel().remoteAddress() + " sleep 4s");
            TimeUnit.SECONDS.sleep(4);
        }

    }
}

клиент

public class Client {

    private static final Logger log = Logger.getLogger(Client.class.getName());

    public static void main(String[] args) throws InterruptedException {
        int port = Integer.parseInt(args[0]);

        for (int i = 0; i < 10; i++) {
            Client cl = new Client("localhost", port);
            cl.start();
            TimeUnit.MILLISECONDS.sleep(500);
        }
    }

    String host;
    int port;

    public Client(String host, int port) {
        this.host = host;
        this.port =port;
    }

    public void start() {
        log.info("Start client running");
        Socket socket = null;
        String info = "";
        try {
            socket = new Socket(host, port);
            InetSocketAddress addr = (InetSocketAddress) socket.getLocalSocketAddress();
            info = String.format("%s:%s", addr.getHostName(), addr.getPort());
            int count = 10;

            OutputStream out = socket.getOutputStream();
            while (count > 0) {
                String outStr = "Output-" + count + "n";
                out.write(outStr.getBytes());
                out.flush();
                count--;
            }
            out.write((info + "-Finish sending").getBytes());
            out.flush();
        } catch (Exception e) {
            log.log(Level.SEVERE, "Client error", e);
        } finally {
            try {
                socket.close();
                log.info(info + "-Client close");
            } catch (IOException e) {
                log.log(Level.SEVERE, "Closing client error", e);
            }
        }
    }
}

клиент при запуске создаст 10 клиентов, подключающихся к серверу. После того, как я бегу и контролирую несколько раз я не находил различий между Java IO и NIO.

Если изменено количество клиентов на 500, я обнаружил, что Java IO действительно создал 500 потоков, однако потребление данных очень быстро. В отличие от этого, приложение java NIO имело гораздо меньше потоков, чем другое, но потребление данных было медленным, и потребовалось больше времени, чтобы закончить все.

Итак, в чем же на самом деле преимущество Java NIO? Создайте меньше потоков для сохранения памяти, но медленнее спектакль.

или я мог сделать это неправильно.

1 ответов


разница в скорости, которую вы замечаете, происходит из-за сна 4s, который появляется в обоих тестовых случаях.

в случае non-NIO, который имеет один поток на запрос, спящий в течение 4 секунд только блокирует этот один запрос. Однако в случае NIO, который имеет гораздо меньшее количество рабочих потоков, он блокирует этот запрос и каждый другой запрос, ожидающий запуска в этом потоке.

таким образом, возникает вопрос, почему мы хотим использовать меньше потоков с NIO подход? И ответ-масштабируемость. Современные операционные системы имеют проблему масштабирования, связанную с количеством потоков, заблокированных в сети IO. Вижу C10K проблема для получения более подробной информации.

В общем, я считаю, что NIO быстрее, или, по крайней мере, у него есть потенциал быть намного быстрее, если:

  1. вы используете его, чтобы избежать копирования буферов вокруг
  2. и вы избежите всего, что может блокировать потоки. например, не блокировать на базе выборки так далее.

Это где асинхронные фреймворки, такие как акка светит.