精华内容
下载资源
问答
  • 【NIO】阻塞与非阻塞
    2021-02-03 13:33:01

    “阻塞”与"非阻塞"与"同步"与“异步"不能简单的从字面理解,提供一个从分布式系统角度的回答。

    1.同步与异步

    同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
    所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。
    换句话说,就是由调用者主动等待这个调用的结果。

    而异步则是相反,调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用*发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

    典型的异步编程模型比如Node.js

    举个通俗的例子:
    你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
    而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

    2. 阻塞与非阻塞

    阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

    阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
    非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

    还是上面的例子,
    你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
    在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

    如果是关心阻塞 IO/ 异步 IO, 参考 Unix Network Programming View Book

    怎样理解阻塞非阻塞与同步异步的区别?

    怎样理解阻塞非阻塞与同步异步的区别?

    更多相关内容
  • 主要介绍了详解socket阻塞与非阻塞,同步与异步、I/O模型,socket网络编程中的同步,异步,阻塞式,非阻塞式,有何联系与区别,本文将详细讲诉。
  •  稍微接触过Verilog HDL的都对阻塞与非阻塞赋值略知一二,也是我们经常强调的重点之一,在课堂上还是有学员问什么不一样呢,为什么我用阻塞赋值也能得出正确的结果呢?  在编写可综合代码的时候,建议大家不要忘...
  • 阻塞与非阻塞赋值

    2021-01-19 22:56:02
     稍微接触过Verilog HDL的都对阻塞与非阻塞赋值略知一二,也是我们经常强调的重点之一,在课堂上还是有学员问什么不一样呢,为什么我用阻塞赋值也能得出正确的结果呢?  在编写可综合代码的时候,建议大家不要忘...
  • 包含thrift五种模式下的例子;阻塞(2种), 非阻塞(3种);可做参考
  • 本文介绍了Verilog阻塞与非阻塞赋值的区别
  • 本文主要讲了IO中同步、异步阻塞、非阻塞的区别。希望对你的学习有所帮助。
  • 主要介绍了php多进程中的阻塞与非阻塞操作,结合实例形式分析了php多进程中的阻塞与非阻塞原理、阻塞控制方法与相关操作技巧,需要的朋友可以参考下
  • FPGA中阻塞赋值与非阻塞赋值原理实验
  • 很多时候我们常常看到同步与异步,阻塞与非阻塞的出现。有的地方直接将同步与阻塞画上了等号。异步与非阻塞画上了等号。事实上这是不对的。同步不等于阻塞,而异步也不等于非阻塞。下面就来仔细的看看同步与异步、...
  • 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值.zip
  • 主要介绍了Linux UDP socket 设置为的非阻塞模式阻塞模式区别的相关资料,需要的朋友可以参考下
  • 聊聊同步、异步、阻塞与非阻塞 聊聊同步、异步、阻塞与非阻塞 聊聊同步、异步、阻塞与非阻塞
  • 主要介绍了php 多进程编程父进程的阻塞与非阻塞,结合实例形式分析了php 多进程编程中父进程的阻塞、等待、子进程退出、非阻塞等相关操作技巧,需要的朋友可以参考下
  • 阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的...非阻塞操作的进程在不能进行设备操作时,并不挂起。被挂起的进程进入sleep状态,被从调度器的运行队列移走,直到等待的条件被满足。
  • 阻塞与非阻塞

    2013-09-11 23:11:51
    最近帮一哥们做一个简单的通信演示小程序,重拾遗忘很久的Windows网络编程,...下面对阻塞非阻塞做一小结,其中有部分内容参考于网络,也许只有亲身体验过的人才能感觉到这平白的总结中蕴含的种种细节痛苦的实践。
  • 本文对网络应用中阻塞通信与非阻塞通信工作机制及实现等问题进行了研究和探讨提出了系统地实现阻塞与非阻塞通信的方法和步骤文中对比了两种不同的网络通信方式分别给出了基于阻塞与非阻塞IO开发高性能网络应用程序的...
  • java NIO(三)之阻塞与非阻塞

    千次阅读 2018-05-31 08:16:58
    阻塞与非阻塞阻塞 传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,...

                                                          阻塞与非阻塞


    阻塞   传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。


    非阻塞  Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。


     1. 通道(Channel):负责连接

       java.nio.channels.Channel 接口:
    |--SelectableChannel
    |--SocketChannel
    |--ServerSocketChannel
    |--DatagramChannel


    |--Pipe.SinkChannel
    |--Pipe.SourceChannel


    2. 缓冲区(Buffer):负责数据的存取


    3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况

    阻塞式

    	@Test
    	public void client() throws Exception{
    		//创建通道
    		FileChannel open = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ);
    		//分配缓冲区
    		ByteBuffer buffer = ByteBuffer.allocate(1024);
    		//创建socket通道
    		SocketChannel open2 = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9988));
    		//读取本地文件,并发送到服务端
    		while(open.read(buffer)!=-1){
    			buffer.flip();
    		open2.write(buffer);
    		buffer.clear();
    		}
    		open2.shutdownOutput();
    		//获取服务端反馈
    		int len=0;
    		while((len=open2.read(buffer))!=-1){
    			buffer.flip();
    			System.out.println(new String (buffer.array(),0,len));
    			buffer.clear();
    		}
    		open.close();
    		open2.close();
    	};
    	
    	@Test
    	public void server() throws IOException{
    		// 获取通道
    		FileChannel open = FileChannel.open(Paths.get("11.jpg"), StandardOpenOption.WRITE,
    				StandardOpenOption.CREATE);
    		ServerSocketChannel open2 = ServerSocketChannel.open();
    		//分配指定大小的缓冲区
    		ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
    		//绑定连接
    		open2.bind(new InetSocketAddress(9988));
    		//获取客户端连接的通道
    		SocketChannel accept = open2.accept();
    		//接收客户端的数据,并保存到本地
    		while(accept.read(byteBuffer)!=-1){
    			byteBuffer.flip();
    			open.write(byteBuffer);
    			byteBuffer.clear();
    		}
    		
    
    		//发送反馈给客户端
    		byteBuffer.put("图片收到了".getBytes());
    		byteBuffer.flip();
    		accept.write(byteBuffer);
    		accept.close();
    		open.close();
    		open2.close();
    	}


    非阻塞式

    	@Test
    	public void client() throws Exception{
    		//1. 获取通道
    		SocketChannel clientSoc=SocketChannel.open(new InetSocketAddress("127.0.0.1", 9988));
    		//2. 切换非阻塞模式
    		clientSoc.configureBlocking(false);
    		//3. 分配指定大小的缓冲区
    		ByteBuffer allocate = ByteBuffer.allocate(1024);
    		//4. 发送数据给服务端
    		Scanner sc=new Scanner(System.in);
    		while(sc.hasNext()){
    			String next = sc.next();
    			allocate.put((LocalDate.now()+"--客户端说"+"\n"+next).getBytes());
    			allocate.flip();
    			clientSoc.write(allocate);
    			allocate.clear();
    		}
    		sc.close();
    		//5. 关闭通道
    		clientSoc.close();
    	}
    	
    	
    	@Test
    	public void Server() throws Exception{
    		//1. 获取通道
    		ServerSocketChannel serSoc=ServerSocketChannel.open();
    		//2. 切换非阻塞模式
    		serSoc.configureBlocking(false);
    		//3. 绑定连接
    		serSoc.bind(new InetSocketAddress(9988));
    		//4. 获取选择器
    		Selector selector = Selector.open();
    		//5. 将通道注册到选择器上, 并且指定“监听接收事件”
    		serSoc.register(selector,  SelectionKey.OP_ACCEPT);
    		//6. 轮询式的获取选择器上已经“准备就绪”的事件
    		while(selector.select()>0){
    			//7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
    			Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
    			while(iterator.hasNext()){
    				//8. 获取准备“就绪”的是事件
    				SelectionKey sk = iterator.next();
    				//9. 判断具体是什么事件准备就绪
    				if(sk.isAcceptable()){
    					//10. 若“接收就绪”,获取客户端连接
    					SocketChannel sChannel = serSoc.accept();
    					//11. 切换非阻塞模式
    					sChannel.configureBlocking(false);
    					//12. 将该通道注册到选择器上
    					sChannel.register(selector, SelectionKey.OP_READ);
    				}else if(sk.isReadable()){
    					//13. 获取当前选择器上“读就绪”状态的通道
    					SocketChannel sChannel = (SocketChannel) sk.channel();
    					//14. 读取数据
    					ByteBuffer buf = ByteBuffer.allocate(1024);
    					int len = 0;
    					while((len = sChannel.read(buf)) > 0 ){
    						buf.flip();
    						System.out.println(new String(buf.array(), 0, len));
    						buf.clear();
    					}
    				}
    			}
    			//15. 取消选择键 SelectionKey
    			iterator.remove();
    		}
    		
    	}

    注册Selector  

    serSoc.register(selector,  SelectionKey.OP_ACCEPT);

    当调用 register(Selector sel, int ops) 将通道注册选择器时,选择器

    对通道的监听事件,需要通过第二个参数 ops 指定。
    可以监听的事件类型(用 可使用 SelectionKey  的四个常量 表示):
        读 : SelectionKey.OP_READ (1)
        写 : SelectionKey.OP_WRITE (4)
        连接 : SelectionKey.OP_CONNECT (8)
        接收 : SelectionKey.OP_ACCEPT (16)

      若注册时不止监听一个事件,则可以使用“位或”操作符连接。

    int interestKey=SelectionKey.OP_ACCEPT|SelectionKey.OP_WRITE;

    SelectionKey:表示 SelectableChannel 和 Selector 之间的注册关系。每次向
    选择器注册通道时就会选择一个事件(选择键)。选择键包含两个表示为整
    数值的操作集。操作集的每一位都表示该键的通道所支持的一类可选择操作。

    方 法 描 述

    int interestOps()                                  获取感兴趣事件集合
    int readyOps()                                    获取通道已经准备就绪的操作的集合
    SelectableChannel channel()             获取注册通道
    Selector selector()                              返回选择器
    boolean isReadable()                         检测 Channal 中读事件是否就绪
    boolean isWritable()                           检测 Channal 中写事件是否就绪
    boolean isConnectable()                    检测 Channel 中连接是否就绪
    boolean isAcceptable()                        检测 Channel 中接收是否就绪

    选择 器(Selector )的应用

    Selector  的常用方法

    方 法 描 述
    Set<SelectionKey> keys()     所有的 SelectionKey 集合。代表注册在该Selector上的Channel
    selectedKeys()                        被选择的 SelectionKey 集合。返回此Selector的已选择键集
    int select()                           监控所有注册的Channel,当它们中间有需要处理的 IO 操作时,该方法返回,并将对应得的 SelectionKey 加入被选择的SelectionKey 集合中,该方法返回这些 Channel 的数量。
    int select(long timeout)         可以设置超时时长的 select() 操作
    int selectNow()                      执行一个立即返回的 select() 操作,该方法不会阻塞线程
    Selector wakeup()                  使一个还未返回的 select() 方法立即返回
    void close()                            关闭该选择器

    UDP的发送

    @Test
    	public void send() throws IOException{
    		DatagramChannel dc = DatagramChannel.open();
    		dc.configureBlocking(false);
    		ByteBuffer buf = ByteBuffer.allocate(1024);
    		Scanner scan = new Scanner(System.in);
    		while(scan.hasNext()){
    			String str = scan.next();
    			buf.put((new Date().toString() + ":\n" + str).getBytes());
    			buf.flip();
    			dc.send(buf, new InetSocketAddress("127.0.0.1", 9898));
    			buf.clear();
    		}
    		
    		dc.close();
    	}
    	
    	@Test
    	public void receive() throws IOException{
    		DatagramChannel dc = DatagramChannel.open();
    		dc.configureBlocking(false);
    		dc.bind(new InetSocketAddress(9898));
    		Selector selector = Selector.open();
    		dc.register(selector, SelectionKey.OP_READ);
    		while(selector.select() > 0){
    			Iterator<SelectionKey> it = selector.selectedKeys().iterator();
    			while(it.hasNext()){
    				SelectionKey sk = it.next();
    				if(sk.isReadable()){
    					ByteBuffer buf = ByteBuffer.allocate(1024);
    					dc.receive(buf);
    					buf.flip();
    					System.out.println(new String(buf.array(), 0, buf.limit()));
    					buf.clear();
    				}
    			}
    			it.remove();
    		}
    	}

    单向管道

    	@Test
    	public void test01() throws IOException{
    		//1. 获取管道
    		Pipe pipe = Pipe.open();
    		
    		//2. 将缓冲区中的数据写入管道
    		ByteBuffer buf = ByteBuffer.allocate(1024);
    		
    		Pipe.SinkChannel sinkChannel = pipe.sink();
    		buf.put("通过单向管道发送数据".getBytes());
    		buf.flip();
    		sinkChannel.write(buf);
    		
    		//3. 读取缓冲区中的数据
    		Pipe.SourceChannel sourceChannel = pipe.source();
    		buf.flip();
    		int len = sourceChannel.read(buf);
    		System.out.println(new String(buf.array(), 0, len));
    		
    		sourceChannel.close();
    		sinkChannel.close();
    	}

    展开全文
  • Linux阻塞与非阻塞

    千次阅读 2019-05-13 17:42:20
    1.阻塞(block)概念:指进程或线程在执行设备操作或管道,或则网络时,不能获取到...2.非阻塞(non_block):进程就算没有获取到资源或没有等到事件发生时不挂起,通常会直接放弃或不断查询, 直到可以进行的位置。也就...

    1.阻塞(block)概念:指进程或线程在执行设备操作或管道,或则网络时,不能获取到资源就被挂起,
    直到满足可操作的条件后在进行操作,被挂起的进程进入休眠状态,从运行队列移走,直到
    等待的条件满足才继续执行。也就是执行到某些函数时必须等待某个事件发生函数才返回。
    2.非阻塞(non_block):进程就算没有获取到资源或没有等到事件发生时不挂起,通常会直接放弃或不断查询,
    直到可以进行的位置。也就是函数的执行不必等待事件发生,一旦执行肯定返回,用返回值来反应函数执行情况。
    3.例如:read读取输入输出设备/dev/tty

    4.read设备文件时发生阻塞

    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<stdio.h>
    #include<stdlib.h>
    
    int main(int argc, char* argv[])
    {
        int fd = open("/dev/tty",O_RDONLY); //打开标准输入输出文件,此时为阻塞
        if(fd == -1){
            perror("open /dev/tty");
            exit(1);
        }
        int ret = 0;
        char buf[1024] = {0};
        while(1){
            ret = read(fd, buf, sizeof(buf));
            if(ret == -1){
                perror("read");
                exit(1);
            }
            else if(ret == 0)
                printf("buf is null\n");
            else if(ret > 0)
                printf("buf is %s\n",buf);
            printf("test\n");
            sleep(1);
        } 
        close(fd);
    
        return 0;
    }
    

    5.直接用O_NONBLOCK设置非阻塞

    int main(int argc, char* argv[])
    {
        int fd = open("/dev/tty", O_RDONLY | O_NONBLOCK); // O_NONBLOCK 设置文件输入输出为非阻塞
        if(fd == -1){
            perror("open /dev/tty");
            exit(1);
        }
        int ret = 0;
        char buf[1024] = {0};
        while(1){
            ret = read(fd, buf, sizeof(buf));
            if(ret == -1){
                perror("read /dev/tty");
                printf("no input,buf is null\n");
            }
            else {
                printf("ret = %d, buf is %s\n",ret, buf);
            }
            sleep(1);
        }
        close(fd);
    
        return 0;
    }
    

    6.用fcntl()函数与O_NONBLOCK设置非阻塞

    int main(int argc, char* argv[])
    {
        int fd = open("/dev/tty", O_RDONLY);
    
        //fcntl()函数设置标准输入输出文件为非阻塞
        int flag = fcntl(fd, F_GETFL);  //第一步:获取文件操作权限
        flag |= O_NONBLOCK;       //第二步:获取的文件属性与O_NONBLOCK相或
        fcntl(fd, F_SETFL, flag); //第三步:再次设置文件操作权限
        int ret = 0;
        char buf[1024] = {0};
        
        while(1){
            ret = read(fd, buf, sizeof(buf));
            if(ret == -1){
                perror("read /dev/tty");
                printf("no input,buf is null\n");
            }
            else {
                printf("ret = %d, buf is %s\n",ret, buf);
            }
            sleep(1);
        }
        close(fd);
    
        return 0;
    }
    
    展开全文
  • 进程与线程 阻塞与非阻塞

    千次阅读 2018-04-16 20:22:34
    阻塞与非阻塞 我要看足球比赛,但是妈妈叫我烧水,电视机在客厅,烧水要在厨房。家里有2个水壶,一个是普通的水壶,另一个是水开了会叫的那种水壶。我可以: 用普通的水壶烧,人在边上看着,水开了再去看球。 (同步...

    进程:CPU执行任务的模块。线程:模块中的最小单元。

    cpu比作我们每个人,到饭点吃饭了。可以点很多菜(cpu中的进程):宫保鸡丁,鱼香肉丝,酸辣土豆丝。每样菜具体包含了哪些内容(cpu每个进程中的线程):宫保鸡丁(详情:黄瓜、胡萝卜、鸡肉、花生米)。而详情构成了宫保鸡丁这道菜,吃了以后不饿。就可以干活了,cpu中的进程里的线程也是同理。当线程完成自己的内容将结果返回给进程,进程返回给cpu的时候。cpu就能处理日常需求。

    • 单进程单线程:一盘炒苦瓜,里面只有苦瓜。
    • 单进程多线程:一盘宫保鸡丁,里面有黄瓜、胡萝卜、鸡肉、花生米


    阻塞与非阻塞

    我要看足球比赛,但是妈妈叫我烧水,电视机在客厅,烧水要在厨房。家里有2个水壶,一个是普通的水壶,另一个是水开了会叫的那种水壶。我可以:

    1. 用普通的水壶烧,人在边上看着,水开了再去看球。(同步,阻塞)这个是常规做法,但是我看球不爽了。
    2. 用普通水壶烧,人去看球,隔几分钟去厨房看看。(同步,非阻塞)这个又大问题,万一在我离开的几分钟水开了,我就麻烦了。
    3. 用会叫的水壶,人在边上看着。(异步,阻塞)这个没有问题,但是我太傻了。
    4. 用会叫的水壶,人去看球,听见水壶叫了再去看。(异步,非阻塞)这个应该是最好的。

    等着看球的我:阻塞

    看着电视的我:非阻塞

    普通水壶:同步

    会叫的水壶:异步

    所以,异步往往配合非阻塞,才能发挥出威力。

    展开全文
  • 非阻塞这样的概念,也相信都曾经产生过误解,比如认为同步就是阻塞、异步就是非阻塞,下面我们先剖析下这几个概念分别是什么含义。 同步: 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回...
  • Verilog中的延时、阻塞与非阻塞赋值仿真设计.doc
  • socket阻塞与非阻塞,同步与异步

    万次阅读 2020-06-18 14:42:52
    一、I/O相关的五个重要概念 第一个概念:用户空间内核空间 1. 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方) 2. 操作系统的核心是内核,独立于...
  • Linux 阻塞与非阻塞 读取文件

    千次阅读 2020-08-25 10:00:45
    阻塞与非阻塞 读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,...
  • 阻塞与非阻塞socket的优缺点

    千次阅读 2020-06-16 14:56:53
    ... 谓阻塞方式的意思是指,当试图对该文件描述符进行读写时,如果当时没有东西可读,或者暂时不可写,程序就进入等待状态,直到有东西可读或者可写为止。...非阻塞,就是进程或线程执行此函数时不必非要等待事件的发生,
  • C++ socket 阻塞与非阻塞

    热门讨论 2011-11-04 11:18:17
    C++ Socket编程示例; 阻塞和非阻塞,涉及多线程编程,以及定时清除服务器连接资源;
  • tcp socket阻塞与非阻塞

    万次阅读 2016-04-05 18:39:30
    1.sock默认为阻塞模式,下面的代码可对sock设置为非阻塞模式  int flags = fcntl(sock, F_GETFL, 0);  fcntl(sock, F_SETFL, flags | O_NONBLOCK); 2.假设当前代码为服务器,并且已经执行过如下代码, 当sock为...
  • 阻塞与非阻塞的对比

    千次阅读 2018-07-22 13:23:06
    阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回。 1、阻塞调用和同步调用不同点: 对于同步调用来说,很多时候当前线程可能还是...
  • 作者|Subranium学校 | 东北大学研究| 城市计算出品 | AI蜗牛车一、引言相信线程,进程,协程, 并发,并行,同步,异步,阻塞和非阻塞这几个概念大家在编程过程中肯定会遇...
  • python3多进程阻塞与非阻塞快速理解

    千次阅读 2020-03-31 12:10:17
    python多进程阻塞和非阻塞 非阻塞: (不需要等待)。 简单来说就是开启几个进程就同时运行几个进程。 比如下面程序,开启3个进程,那么程序一运行的时候立马执行3个进程同时调用function方法,不需要等待进程1执行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 487,429
精华内容 194,971
关键字:

阻塞与非阻塞