精华内容
下载资源
问答
  • 今天读到一篇博客,发现对Java异步非阻塞编程概念有些模糊了,趁此整理了一下常用的几种编程方式。 方式一:同步调用 当主线程发起IO操作时,会被阻塞,一直等到数据返回,此时主线程状态是Runnable状态。产生的问题...


    今天读到一篇博客,发现对Java异步非阻塞编程概念有些模糊了,趁此整理了一下常用的几种编程方式。

    方式一:同步调用

    当主线程发起IO操作时,会被阻塞,一直等到数据返回,此时主线程状态是Runnable状态。产生的问题是:主线程在IO等待的过程中,线程资源没有得到充分的利用,对于大量IO场景的业务吞吐量会有一定限制。如下图:
    在这里插入图片描述

    方式二:Future方式异步调用

    使用future异步获取结果代码示例如下:

    ThreadPoolExecutor executor = new ThreadPoolExecutor(......);
         Future<Boolean> future = (Future<Boolean>) executor.submit(new Runnable() {
                @Override
                public void run() {
                    // 复杂计算
                }
         });
         boolean result = future.get(1000, TimeUnit.MILLISECONDS);	
    

    主线程等待示意图如下,此时主线程在等待时间内需要让出cpu,cpu可以做些其他事情,但主线程仍然阻塞(主线程由Runnable状态变为waiting状态):
    在这里插入图片描述
    上述示意代码返回的Future实例是FutureTask类,类图如下,详细分析可参考FutureTask-get方法。
    在这里插入图片描述

    方式三:Callback回调方式

    Callback回调方式可参考示意图如下:
    在这里插入图片描述
    对Callback回调机制简要举个例子如下:

    // 回调接口
        public interface ICallback {
         	public void callback(String parameter);
        }	
         
         // 异步执行的业务
        public class CallbackTest {
        	private ExecutorService threadPool = Executors.newFixedThreadPool(2);
        	public void doSyncInvoke(ICallback callback) {
        		Thread thread = new Thread(new Runnable() {
                	@Override
                	public void run() {
                    	System.out.println("子线程任务处理");
    
                    	// 开始处理业务
                    	String result = "this is process result";
    
                    	// 执行回调函数
                    	callback.callback(result);
                	}
            	});
    
            	// 交给线程池执行
            	threadPool.submit(thread);
            	threadPool.shutdown();
        	}
        }
        
        // 主函数调用
        CallbackTest callbackTest = new CallbackTest();
        callbackTest.doSyncInvoke(new ICallback() {
                @Override
                public void callback(String parameter) {
                    System.out.println("执行回调函数......");
                }
        });
        
        /**
         *输出:
         * 子线程任务处理
         * 执行回调函数......
         **/
    

    另外,Java8提供了CompletableFuture可使用,使用示例如下:

    // 输出:hello world Java
         CompletableFuture.supplyAsync(() -> "Hello") // 异步处理,类似上述doSyncInvoke
                    .thenApply(s -> s + " world ") // 回调函数
                    .thenApply(String::toLowerCase) // 回调函数
                    .thenCombine(CompletableFuture.completedFuture("Java"), (s1, s2) -> s1 + s2)
                    .thenAccept(System.out::println);	
    

    另外CompletableFuture的类图如下:
    在这里插入图片描述

    方式四:Java9 Reactive Streams

    该种方法不再细述,可参考相关资料。

    参考:https://mp.weixin.qq.com/s/AVMN8jyqMXWhE9bRs_e0aQ

    欢迎关注微信公众号:方辰的博客
    在这里插入图片描述

    展开全文
  • 灵活且超轻量级的库,用于使用 Future 模式、回调(NodeJS 风格)和异步非阻塞编程。 动机 该库的第一个目标是为 Java 8 提供模式的轻量级实现。此外,该库还提供对 Java 流水线的支持。 第二个目的是演示 Java 8 ...
  • # 真正意义上的 异步IO 是说内核直接将数据拷贝至用户态的内存单元,再通知程序直接去读取数据。 # select / poll / epoll 都是同步IO的多路复用模式 1.同步和异步 # 同步和异步关注的是消息通信机制 # 所谓...

    # 真正意义上的 异步IO 是说内核直接将数据拷贝至用户态的内存单元,再通知程序直接去读取数据。

    # select / poll / epoll 都是同步IO的多路复用模式

    1.同步和异步

    # 同步和异步关注的是消息通信机制

    # 所谓同步,就是在发出一个*调用*时,没得到结果之前,该*调用*就不返回。但是一旦调用返回就得到返回值了,*调用者*主动等待这个*调用*的结果

    # 所谓异步,就是在发出一个*调用*时,这个*调用*就直接返回了,不管返回有没有结果。当一个异步过程调用发出后,*被调用者*通过状态,通知来通知*调用者*,或者通过回调函数处理这个调用

    2.阻塞和非阻塞

    # 阻塞和非阻塞关注的是程序在等待调用结果时的状态

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

    # 非阻塞调用是指在不能立即得到结果之前,该调用不会阻塞当前线程

    通俗例子一:

    #老张爱喝茶

    展开全文
  • Spring MVC 构建于 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什么是同步阻塞式 I/O 模型呢?就是说,每一个请求对应一个线程去处理。 了解了 Spring MVC 之后,再来说说 Spring WebFlux: 上图左边,官方给...

    一、什么是 Spring WebFlux

    Spring MVC 构建于 Servlet API 之上,使用的是同步阻塞式 I/O 模型,什么是同步阻塞式 I/O 模型呢?就是说,每一个请求对应一个线程去处理。

    Spring WebFlux 是一个异步非阻塞式的 Web 框架,它能够充分利用多核 CPU 的硬件资源去处理大量的并发请求。

     

    二、WebFlux 的优势&提升性能?

     

    WebFlux 内部使用的是响应式编程(Reactive Programming),以 Reactor 库为基础, 基于异步和事件驱动,可以让我们在不扩充硬件资源的前提下,提升系统的吞吐量和伸缩性。

    看到这里,你是不是以为 WebFlux 能够使程序运行的更快呢?量化一点,比如说我使用 WebFlux 以后,一个接口的请求响应时间是不是就缩短了呢?

    抱歉了,答案是否定的!以下是官方原话:

    Reactive and non-blocking generally do not make applications run faster.

    WebFlux 并不能使接口的响应时间缩短,它仅仅能够提升吞吐量和伸缩性

     

    三、WebFlux 应用场景

    上面说到了, Spring WebFlux 是一个异步非阻塞式的 Web 框架,所以,它特别适合应用在 IO 密集型的服务中,比如微服务网关这样的应用中。

    PS: IO 密集型包括:磁盘IO密集型网络IO密集型,微服务网关就属于网络 IO 密集型,使用异步非阻塞式编程模型,能够显著地提升网关对下游服务转发的吞吐量。

     

     四、选 WebFlux 还是 Spring MVC?

    首先你需要明确一点就是:WebFlux 不是 Spring MVC 的替代方案!,虽然 WebFlux 也可以被运行在 Servlet 容器上(需是 Servlet 3.1+ 以上的容器),但是 WebFlux 主要还是应用在异步非阻塞编程模型,而 Spring MVC 是同步阻塞的,如果你目前在 Spring MVC 框架中大量使用非同步方案,那么,WebFlux 才是你想要的,否则,使用 Spring MVC 才是你的首选。

    在微服务架构中,Spring MVC 和 WebFlux 可以混合使用,比如已经提到的,对于那些 IO 密集型服务(如网关),我们就可以使用 WebFlux 来实现。

     

    五、异同点

    相同点:

    • 都可以使用 Spring MVC 注解,如 @Controller, 方便我们在两个 Web 框架中自由转换;
    • 均可以使用 Tomcat, Jetty, Undertow Servlet 容器(Servlet 3.1+);
    • ...

    注意点:

    • Spring MVC 因为是使用的同步阻塞式,更方便开发人员编写功能代码,Debug 测试等,一般来说,如果 Spring MVC 能够满足的场景,就尽量不要用 WebFlux;
    • WebFlux 默认情况下使用 Netty 作为服务器;
    • WebFlux 不支持 MySql;

    六、快速入门

    7.1 添加 webflux 依赖

    新建一个 Spring Boot 项目,在 pom.xml 文件中添加 webflux 依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    

    7.2 定义接口

    新建一个 controller 包,用来放置对外的接口类,再创建一个 HelloWebFluxController.class 类,定义两个接口:

    package site.exception.springbootwebfluxhello.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import reactor.core.publisher.Mono;
    import site.exception.springbootwebfluxhello.entity.User;
    
    
    @RestController
    public class HelloWebFluxController {
    
        @GetMapping("/hello")
        public String hello() {
            return "Hello, WebFlux !";
        }
    
        @GetMapping("/user")
        public Mono<User> getUser() {
            User user = new User();
            user.setName("xrj");
            user.setDesc("hello");
            return Mono.just(user);
        }
    
    
    }
    
    

    User.java:

    package site.exception.springbootwebfluxhello.entity;
    
    public class User {
    
        /**
         * 姓名
         */
        private String name;
        /**
         * 描述
         */
        private String desc;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    }
    

    以上控制器类中,我们使用的全都是 Spring MVC 的注解,分别定义了两个接口:

    • 一个 GET 请求的 /hello 接口,返回 Hello, WebFlux !字符串。
    • 又定义了一个 GET 请求的 /user方法,返回的是 JSON 格式 User 对象。

    这里注意,User 对象是通过 Mono 对象包装的,你可能会问,为啥不直接返回呢?

    在 WebFlux 中,Mono 是非阻塞的写法,只有这样,你才能发挥 WebFlux 非阻塞 + 异步的特性。

    补充:在 WebFlux 中,除了 Mono 外,还有一个 Flux,这哥俩均能充当响应式编程中发布者的角色,不同的是:

    • Mono:返回 0 或 1 个元素,即单个对象。
    • Flux:返回 N 个元素,即 List 列表对象。

    7.3 测试接口

    启动项目,查看控制台输出:

    启动 WebFlux 项目

    当控制台中输出中包含 Netty started on port(s): 8080 语句时,说明默认使用 Netty 服务已经启动了。

    展开全文
  • 同步异步、阻塞非阻塞 个人认为同步和异步是更抽象的概念,是相对的任务而言的。而阻塞和非阻塞就就字面的意思是对当前的进程或线程而言的。 概念之间的区别同步与异步 同步与异步在不同的场景下有不同的概念,在...

    同步异步、阻塞非阻塞

            个人认为同步和异步是更抽象的概念,是相对的任务而言的。而阻塞和非阻塞就就字面的意思是对当前的进程或线程而言的。

     

    概念之间的区别

    同步与异步

            同步与异步在不同的场景下有不同的概念,在IO模型中的同步异步,主要区别在当任务A调用任务B的过程中,进程A是否继续进行。 

            如果A等待B的结果,则为同步;

            如果A不等待B的结果,则为异步;

            同步状态下任务A的执行时依赖于任务B的,任务A成功是依赖于成功B的。而异步模式下两者是不相关的。

            异步的实现方式大概有三种:状态、通知和回调。状态就是任务A去查询任务B的结果如何 ;通知就是等任务B执行完成之后通知任务A来实现;回调就是任务A定义个回调函数,当任务B结束后会自动调用回调函数;

    阻塞与非阻塞

            阻塞和非阻塞的主要区别在,任务A等待B的结果的过程中,任务A是否会被挂起? 如果A等待的过程中不会挂起,则为阻塞; 如果A不等待的过程中不会挂起,则为非阻塞。

            同步阻塞的情况下,任务A会挂起,同步非阻塞的情况下任务A并不挂起。不挂起的情况下任务A保留有响应信号的能力。

            非阻塞的情况下并不会导致线程切换(只是不强制进行线程切换,如果该线程的时间片用完还是会切换的),可能效率更高,cpu利用率也更高,但是cpu可能会无意义空转,这样又会导致性能降低,所以使用何种方式需要看当前的系统情况。

            上面两点似乎被分的很清楚,但是实际上这两个概念我认为指的是同一件事情,站的角度不同而已,过分的强调概念是无意义的。同步和异步更多的是两个任务之间数据通信方式,而阻塞非阻塞,则是站在当前线程自身的角度考虑是否可以在保留进程不挂起而继续进行任务来看的。

    5种IO模型

            要了解IO模型先要理解一linux类的系统下计算机的IO基本概念,5种IO模型实际上指的都是网络编程中的IO,数据从网络读取后先会被放入内核区,而后从内核区传入用户区。 
    5种IO模型中前四种全部都是同步IO只有异步IO,这里的同步和异步区别在于同步IO会在数据到达内核区的等待过程中进行各种方式的检查,如果查到了有数据到达了内核区则进行阻塞,因此整个IO的流程是分成2个阶段的。而异步IO的模式是只有数据完成了从内核区到用户区的复制之后才有通知。 而同步IO中根据第一阶段的不同策略又分成很多的不同模型。

    阻塞式I/O

            应用进程在调用recvfrom,后阻塞直至数据到达用户区之后才恢复。从应用进程的角度上说这是很合理而高效的,从性能的角度来说可以见上文中的讨论,首先他会引起线程切换,其次其cpu利用率低。 



    非阻塞式I/O

            应用进程在调用recvfrom的情况下并阻塞,而是返回一个为准备好的返回值,这时候应用进程可以继续运行,处理一些其他事情。通过这种轮询的方式查询是否有数据到达内核区,如果内核区有数据则需要阻塞应用线程,等待数据读取至用户区之后进行处理。 

            非阻塞I/O看起来很傻,不停的循环,但是这样有两个好处,第一个是不会强制进行线程的切换,线程切换的代价是很大的,其次在两次查询直接可以用来做一些其他的事情,用户线程保有一定的响应能力。 



    I/O复用模型

            非阻塞式I/O中说到了采用轮询的方式查看是否有数据到达内核区,单线程的来看这个问题其实很傻,但是网络IO通常不是单个线程的。会有很多线程同时进行I/O读写,因此我们可以依次检测多个I/O读写任务,如果有某个任务所指定的数据到达则返回这样效率就高得多了,这就是所谓的I/O复用。 
            其实这是网络模型中最为常用的模式,平时所谓的select、poll和epoll都是I/O复用模型,只是细节上略有区别,具体的区别在后面讨论。 

            读取的两个阶段有2次调用2次返回,在第一个阶段是很多I/O读取任务共用的,因此效率还是比较高的。 


    信号驱动I/O 

            信号驱动I/O我并不是很了解,目前的理解是linux类的程序下允许注册一个信号处理函数,我们可以用这种方式来处理IO,首先注册一个信号处理函数,然后应用程序继续进行,当有数据到达内核区后,会有一个信号返回给当前应用进程,当前引用进程进入信号处理过程,信号处理过程中会将数据拷贝至用户区的过程依然是阻塞的。 
            其实这里其实看出来,所谓的阻塞、非阻塞和同步、异步,其实是一件事情,只是在不同的语境下有些细微的区别而已,信号驱动I/O的第一个阶段实际上就是典型的异步通知过程。但是因为其第二个阶段需要阻塞,因此整个信号驱动I/O被归类为同步I/O。 

    异步I/O 
            异步I/O的模型其实就是两个阶段均为异步的方式,用户进程异步调用函数后,检测数据的信号,但是用户线程自身并不挂起,而是继续运行,当数据完成了2个阶段的过程,读取至用户区之后才会通知应用程序。 

    这种方式和阻塞式I/O的区别仅仅在于用户线程是否在两个阶段均阻塞。 



    模型之间的讨论 

            其实对于典型的服务器环境,基本上都是默认采用I/O复用模型的,这一点从模型自身的特性就可以看出。网络I/O中即使采用非阻塞的方式其实本身也没有太大的意义,因为没有数据到来,那处理程序也没有其他的事情要做。而且从编程的角度上来说,I/O复用这种同步的编程模式也更利于理解,不会使得程序显得很混乱。 
    关于效率问题,在上一章的讨论中以及讨论过了并不存在非阻塞效率更高的说法,只是在不同场景下有各自优势而且,但是在绝大多数场景下依然是IO复用更高效。

            下面附上几中不同的I/O状态比较图:


     

    IO复用的几中方式select、poll、epoll

    select

            首先select只有一个函数,创建、注册等待都是一次完成的。 
    特性 
            首先将fd_set从用户空间拷贝到内核区,然后注册回调函数 __pollwait。 
    回调函数的主要工作就是把当前线程挂到设备的等待队列中,不同的设备有不同的等待队列,如果该设备有个响应的响应(比如网络中读取的I/O)则会唤醒该设备等待队列上的进程,___pollwait方法会返回一个描述读写操作是否就行的mask掩码,根据这个掩码给fd_set赋值。 如果遍历fd_set都没有一个可读写的mask掩码,这调用会 schedule_timeout将select线程进入睡眠,如果设备驱动自身资源可读或者,超时一定时间限都没人唤醒,则会唤醒当代队列上的线程重新遍历fd_set判断有没有就绪的fd。 
    缺点 
            每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 ;同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 ,尤其是在连接数量很多,但是活跃连接并不多的情况下。 select支持的文件描述符数量太小了,默认是1024(64位系统是2048)。

    poll

            poll和select基本上类似,区别是采用链表的形式去组织数据,所以没有数量限制。但是前两个问题依然存在

    epoll

            epoll的实现和上面两者有很大的不同,epoll分为三个函数,分别表示创建,注册和阻塞三个情况。

    这样在注册时会将epoll的句柄从用户区拷贝到内核区,所以只有一次复制,而不是每次等待都要复制,不存在第一个问题。 
    epoll为每个fd指定一个回调函数,当设备唤醒的时候就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表,epoll_wait要做的工作其实就是定期查看这个链表有没有就绪的fd就好,所以不需要遍历fd,不存在第二个问题。

            而且由于不需要遍历也不存在低活跃连接数量下效率低下的问题。 epoll没有fd上限,一般1G内存可以有10w个连接,与内存大小相关,而且可以修改。不存在第三个问题。

            此外还有另一种说法,epoll采用mmap内存映射技术将内核区与用户区映射为同一片地方以减少系统复制代价,不清楚具体用在哪里。

            epoll和select、poll之间最主要的区别还是前者基于回调机制进行响应,而select和poll基于系统调用,让内核遍历所有fd进行查询是否有设备就绪。

            epoll本身还分为电平触发和边缘触发 
            电平触发(条件触发)LT模式:就是当fd就绪后进行通知,如果此次通知后没有操作响应,则下次依然通知,可用在阻塞模式也可以用在非阻塞模式。 
            边缘触发ET模式:就是当fd就绪后进行通知,但是如果此次没有响应操作,则下次不会通知。但只可以用在非阻塞模式下。 
    通常来说边缘触发效率更高,因为可以减少重复epoll的次数。

    展开全文
  • AIO(异步非阻塞

    千次阅读 2018-02-22 13:55:26
    异步非阻塞AIO编程,在NIO基础之上引入了异步通道的概念,并提供了异步文件和异步套接字的实现,从而在真正意义上实现了异步非阻塞,之前我们学习的NIO只是非阻塞而并非异步。而AIO它不需要通过多路复用器对注册的...
  • 但在这当中,发现一些概念区分起来很难,比如并发和并行,同步和异步,阻塞和非阻塞,但是这些概念却很重要。因此在此把它总结下来。并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间...
  • 对于Node开发者来说,非阻塞异步编程是他们引以为傲的地方。而在JDK8中,也引入了非阻塞异步编程的概念。所谓非阻塞异步编程,就是一种不需要等待返回结果的多线程的回调方法的封装。使用非阻塞异步编程,可以很大...
  • 真正的 Tornado 异步非阻塞

    万次阅读 2017-05-31 16:46:35
    其中 Tornado 的定义是 Web 框架和异步网络库,其中他具备有异步非阻塞能力,能解决他两个框架请求阻塞的问题,在需要并发能力时候就应该使用 Tornado。但是在实际使用过程中很容易把 Tornado 使用成异步阻塞框架,...
  •  刚开始接触socket的编程的时候,遇到了很多的问题,费了很大劲搞懂。其实往往都是一些比较基本的知识,但是都是很重要的,只要对其熟练的掌握后,相信对基于网络的编程会有很大的提高,呵呵。  就拿...
  • @Async spring提供的,使用时是通过线程执行的,spring会提供默认的线程池(同样底层是ThreadPool),我们也可以自定义线程池代替...所以我认为只能算堵塞的一种方式,不能算响应式异步。 简单用法 https://www...
  • 异步的套接字通道时真正的异步非阻塞I/O,对应于UNIX网络编程中的事件驱动I/O(AIO)。他不需要过多的Selector对注册的通道进行轮询即可实现异步读写,从而简化了NIO的编程模型。jdk7以前的nio是非阻塞IO,操作系统...
  • 1.什么是同步,什么是异步? 定义:同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)。同步,就是调用某个东西是,调用方得等待这个调用返回结果才能继续往后执行。异步,...
  • 异步就是异步,别扯 异步阻塞 异步非阻塞的 <Unix网络编程>,POSIX标准。都没有提到过 哪两个名词,异步就是异步。只有同步时候才有 阻塞和非阻塞 的说法。 都tm异步了,还阻不阻塞个jb 还有 百度的这个,...
  • NodeJs 异步非阻塞

    2019-09-09 17:04:12
    那么在了解NodeJs异步非阻塞机制之前,你是否了解同步异步,阻塞和非阻塞? 同步与非同步:更面向非IO代码 阻塞与非阻塞:更面向IO代码 什么是同步机制? 同步就是必须等待上一个函数执行完毕,才能继续向下执行 ...
  • 参考Tornado 源码分析 - 异步篇Tornado 框架中异步非阻塞编程代码说明Tornado之源码分析(一)异步客户端篇tornado分析(1).基础小结【优化tornado阻塞任务的三个选择】
  • 面试问我同步、异步、阻塞非阻塞,答的并不是很好,回来后必然要出一篇博文加深印象了
  • 用一个最简单的例子说明异步非阻塞Socket的基本原理和工作机制
  • 许多概念,诸如:同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)等,初学者往往迷惑不清,只知其所以而不知起所以然。  异步方式指的是发送方不等接收方响应,便接着发下个数据包的通信方式;而同步指发送...
  • 其中,第一个链接“/list”的设计使用了非阻塞异步编程方法实 现,通过调用OrderFuture来执行分页查询;第二个链接“/list1”,没有 使用非阻塞异步编程方法,直接调用OrderRestService实现了相同的 功能。 没有使用...
  • 网络编程时的同步、异步、阻塞、非阻塞? 同步:函数调用在没得到结果之前,没有调用结果,不返回任何结果。 异步:函数调用在没得到结果之前,没有调用结果,返回状态信息。 阻塞:函数调用在没得到结果之前,当前线程挂起。...
  • 处理大并发之一 对异步非阻塞的理解 阻塞非阻塞对比阻塞与非阻塞 IO的阻塞与非阻塞的解释异步IO优缺点异步IO与轮询技术理想的异步IO模型参考资料  在研究nginx和Node.js的时候常会遇到异步...
  • net_skeleton :异步非阻塞多协议网络的C/C 库
  • 同步异步阻塞非阻塞杂记

    万次阅读 2017-11-10 12:19:18
    gevent实现的协程是同步非阻塞还是异步非阻塞? gevent是一个使用完全同步编程模型的可扩展的异步I/O框架。 IO是不是阻塞的和协程是没有关系的,python本来就能支持非阻塞IO, 比如在linux只要用API,更改了...
  • 网络编程方面有些概念被经常提到,如:阻塞、非阻塞等,对这些的概念理解很模糊,所以这次来详细的学习下。 正文 同步与异步 &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;同步是指一个任务的完成...
  • 有些文章将这四个作了两两组合,于是就有了:异步阻塞和异步非阻塞,可以明确的说,这完全是牵强之理解,无论<Unix网络编程>一书中所列的I/O模式,还是POSIX标准,都没有提这两个概念。异步就是异步!只有同步...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 86,419
精华内容 34,567
关键字:

异步非阻塞编程