V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
ojh
V2EX  ›  问与答

关于异步非阻塞中的非阻塞的疑惑

  •  
  •   ojh · 2022-04-10 16:37:50 +08:00 · 953 次点击
    这是一个创建于 746 天前的主题,其中的信息可能已经有所发展或是发生改变。

    网上的帖子或者书本解释的阻塞与非阻塞都是简单说线程执行任务有没有被挂起的区别,但是我发现这个所谓的线程他们并没有准确进行定义。

    1. 多线程实现的异步,调用线程没有被阻塞,但是新开启的线程执行有些异步任务比如 HTTP 请求就会被阻塞
    2. 单线程(或多线程)事件轮询实现的异步,除了事件轮询的线程会在等待 select 时候阻塞,其他 IO 读写是不会被阻塞的

    请问一下大佬看下我列的 1 、2 见解是否有误。Netty 强调的非阻塞以及 Servlet 3.1 的非阻塞到底指的是那种非阻塞,单单的调用线程不会被阻塞还是指基本上不会有线程被阻塞

    1194129822
        1
    1194129822  
       2022-04-10 21:02:53 +08:00
    单线程没法实现异步。异步就相当于无限缓冲区的生产者消费者模式,所以才有流量控制,背压。这里面设计多线程,io ,网络协议问题太复杂。JS 的单线程异步,实际上是执行引擎的单线程,并不是没有 io 线程。
    阻塞不阻塞是针对 IO 和网络协议的,OIO 是阻塞的,NIO ( epoll 、),AIO ( IOCP )则不(全)是阻塞的。如果 httpclient 使用的 NIO ,则不会阻塞线程,一个线程可以创建几万连接都可以,一个连接也可以发出很多请求,但是 http 线头阻塞( HOL )问题,一个 HTTP 连接发出的请求要顺序返回,所以一般一个连接就发送一个请求,所以从协议看 http 是一个同步的协议。
    netty 非阻塞就是 epoll 模型,epoll 通过线程的 loop ( selector 线程)来检查是否有 io 就绪事件。你现在这些困惑就是对这块系统知识不了解而已,你学一下多线程,netty 自然就能有答案了。而异步的 Servlet 让连接和处理的线程分开了,和这里并不是一个概念。
    所有不在 Netty eventloop 线程处理 OIO ( JDBC )当然就不会有阻塞。异步 Servlet 变得和 eventloop 有点相似,让连接和业务分开了,但是处理 OIO(JDBC)之类还是会阻塞业务线程的。
    所以全链路异步基本很难实现的,现实是消费者速度永远更不上生产者,也不能有无限缓冲区,所以才有了线程池的拒绝策略。异步并不能提高处理速度,应该说其实降低了一点速度,但是提高了资源的利用率。
    ojh
        2
    ojh  
    OP
       2022-04-10 21:32:29 +08:00
    好吧,然后你说到 HttpClient 用到 NIO ,它跟 Java 11 新的 HttpClient (基于多线程或者说线程池),这两个库的底层的不同应该就是我上面列的两点的区别吧,前者肯定叫非阻塞。那后者算非阻塞吗,即便发底层发请求的线程是阻塞的,我主要问的是这个,因为我觉得对于调用线程来说它没被阻塞,但是对于底层等待 HTTP 响应的那条线程又被阻塞的。
    ojh
        3
    ojh  
    OP
       2022-04-10 21:32:41 +08:00
    @1194129822 好吧,然后你说到 HttpClient 用到 NIO ,它跟 Java 11 新的 HttpClient (基于多线程或者说线程池),这两个库的底层的不同应该就是我上面列的两点的区别吧,前者肯定叫非阻塞。那后者算非阻塞吗,即便发底层发请求的线程是阻塞的,我主要问的是这个,因为我觉得对于调用线程来说它没被阻塞,但是对于底层等待 HTTP 响应的那条线程又被阻塞的。
    ojh
        4
    ojh  
    OP
       2022-04-10 21:38:01 +08:00
    @1194129822 看了下 Servlet 3.1 的非阻塞,估计底层也是用 NIO 这种 Eventloop 形式才叫非阻塞的吧
    1194129822
        5
    1194129822  
       2022-04-10 23:36:03 +08:00
    异步是异步(线程),阻塞是阻塞( IO ,锁等),这两个不是一个概念的东西。异步可以阻塞,只是在 JS 里,没有阻塞的概念。我记得不错的话,Java11 的 HttpClient 依然使用的是阻塞 IO, 底层线程池是 ForkJoinPool.commonPool(),这个线程池只有 nCpu-1 个线程,适合做的是内存计算问题。而且是 Stream ,CompletableFuture ,CHM 所用到的线程池。所以 Java11 HttpClient 虽然 API 设计很好,其实在服务端生产价值有限。非阻塞的 HttpClient ,如 Spring WebFlux 的 WebClient ,一个线程发出几千个请求不是问题。
    1194129822
        6
    1194129822  
       2022-04-10 23:37:45 +08:00
    NIO 也有阻塞模式,所以这里概念的确很杂。AIO 概念上就是非阻塞的,但是背压问题,linux 没有实现。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5571 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 03:01 · PVG 11:01 · LAX 20:01 · JFK 23:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.