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 быстрее, или, по крайней мере, у него есть потенциал быть намного быстрее, если:
- вы используете его, чтобы избежать копирования буферов вокруг
- и вы избежите всего, что может блокировать потоки. например, не блокировать на базе выборки так далее.
Это где асинхронные фреймворки, такие как акка светит.