文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

为什么高手都要用非阻塞IO?

2024-11-29 21:07

关注

传统的I/O操作是阻塞的,这意味着当一个I/O操作进行时,当前的执行体会被挂起,进入等待状态,直到I/O结果返回,执行体才会继续处理后续的逻辑。这就像你去图书馆前台借一本非常热门的书,但书已经被借出。为了得到这本书,你选择站在前台等待,直到这本书被归还。等待的过程中,你不能去干其它任何事情。

非阻塞I/O更像是这样:你去借那本热门书籍,但被告知现在没有。这时,你留下联系方式并告诉图书管理员,一旦书归还,请通知你。然后你可以自由地去参加其他活动。

在借书的这个例子中,你不用浪费大量的时间在等待上,同样的时间你可以做更多的事,可以说,非阻塞I/O极大的提高了系统运行效率。另外还有很多同学说非阻塞IO快,阻塞IO慢,真的是这样吗?

本文,我们将深入探讨阻塞I/O遇到的问题,非阻塞I/O的原理、优势及其实现方法,帮助大家更好地理解和应用这一技术。

阻塞IO的真正问题

阻塞IO为什么被诟病?

在高并发场景下,如果使用阻塞I/O模型,每个请求都需要创建一个新的线程来处理。当这些请求中有大量操作处于I/O等待状态时,虽然CPU能够切换到其他任务继续执行,但创建和管理大量线程本身也会消耗系统资源,包括内存和用于线程上下文切换的CPU时间,从而影响系统的整体性能和可扩展性。

非阻塞IO的基本原理

什么是非阻塞IO?

正如上面借书的例子,当IO操作发生时,我们无需等待,可以去干别的事,只有IO操作返回时,我们才需要处理IO返回的结果,这就是非阻塞IO的本质。

非阻塞IO可以解决阻塞IO的内存占用过大和上下文切换频繁问题,下边我将介绍几个典型的非阻塞IO模型,方便大家理解其中的原理。

Java NIO

Java NIO(New I/O)引入了非阻塞I/O机制,通过Channel和Buffer来处理数据,使用Selector来管理多个Channel。

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.net.InetSocketAddress;
import java.util.Iterator;

public class NIOServer {
    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverSocket = ServerSocketChannel.open();
        serverSocket.bind(new InetSocketAddress("localhost", 8080));
        serverSocket.configureBlocking(false);
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            Iterator keys = selector.selectedKeys().iterator();
            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();
                if (key.isAcceptable()) {
                    SocketChannel client = serverSocket.accept();
                    client.configureBlocking(false);
                    client.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    SocketChannel client = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(256);
                    client.read(buffer);
                    System.out.println("Received: " + new String(buffer.array()).trim());
                }
            }
        }
    }
}

Python asyncio

asyncio是Python标准库中的一个库,提供了异步I/O支持。它基于事件循环(event loop),可以调度和执行异步任务(coroutines)。

import asyncio

async def handle_client(reader, writer):
    data = await reader.read(100)
    message = data.decode()
    print(f"Received: {message}")

    writer.write(data)
    await writer.drain()
    writer.close()

async def main():
    server = await asyncio.start_server(handle_client, '127.0.0.1', 8888)
    async with server:
        await server.serve_forever()

asyncio.run(main())

Node.js的事件驱动模型

图片

Node.js使用事件驱动模型和非阻塞I/O操作,基于libuv库实现。libuv是一个跨平台的异步I/O库,封装了不同操作系统的I/O多路复用机制(如epoll、kqueue、IOCP等)。

const http = require('http');

const server = http.createServer((req, res) => {
    if (req.method === 'GET') {
        res.writeHead(200, { 'Content-Type': 'text/plain' });
        res.end('Hello, World!\n');
    }
});

server.listen(8080, '127.0.0.1', () => {
    console.log('Server running at http://127.0.0.1:8080/');
});

Go语言的goroutine

图片

Go语言通过goroutine和channel提供了轻量级的并发支持。goroutine是Go语言中的轻量级线程,或者也叫协程,通过channel进行通信和同步。select语句用于监听多个channel的操作,实现非阻塞I/O。

package main

import (
    "fmt"
    "net"
    "bufio"
)

func handleConnection(conn net.Conn) {
    defer conn.Close()
    reader := bufio.NewReader(conn)
    for {
        message, _ := reader.ReadString('\n')
        fmt.Printf("Received: %s", message)
        conn.Write([]byte(message))
    }
}

func main() {
    listener, _ := net.Listen("tcp", "localhost:8080")
    defer listener.Close()
    for {
        conn, _ := listener.Accept()
        go handleConnection(conn)
    }
}

非阻塞I/O的设计共性

非阻塞IO更快吗?

对于单次IO,从发起到收到响应,其中主要有三段时间:请求数据从客户端到服务端的传输时间、服务端的处理时间、响应数据从服务端到客户端的返回时间。对于这三段时间,非阻塞IO和阻塞IO都没有任何影响力或者说影响甚小,它们都不会因为使用非阻塞IO而变的更快。

但是非阻塞IO因为更优的内存使用效率,服务器可以支撑更大的并发访问,在繁忙的系统中,如果存在因为内存分配或者线程调度而导致请求接入等待的情况,非阻塞IO一定程度上会降低请求接入的平均时间,从而让服务端的处理更快一些。不过这是非阻塞IO结合协程机制的效果,单纯非阻塞IO没有这个能力。

以上就是本文的主要内容。非阻塞I/O通过更高效的资源利用和更低的线程管理开销,显著提升了系统在高并发场景下的性能和扩展性。尽管它不能直接加快单次I/O操作的速度,但其在整体性能优化方面的优势使其成为现代软件系统中不可或缺的重要部分。掌握非阻塞I/O技术,对于开发高性能、高可扩展性的应用至关重要。希望本文能帮助大家更好地理解和应用这一技术。

来源:萤火架构内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯