关于使用异步框架发送 http 请求的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yumenawei
V2EX    Java

关于使用异步框架发送 http 请求的疑问

  •  
  •   yumenawei 2021-04-28 17:32:17 +08:00 3628 次点击
    这是一个创建于 1703 天前的主题,其中的信息可能已经有所发展或是发生改变。
    业务流程:
    客户端请求服务端 -> 服务端请求多个第三方 http api 获取数据 -> 服务端聚合处理第三方 api 的数据,返回给客户端

    在第二个步骤中,我们使用 vert.x web client 这个异步框架同时发起多个 http 请求,当请求完成后将结果放到一个 future 中。调用线程调用 future.get 阻塞住,等待异步请求结果返回。

    我的问题是:
    听说这个地方使用异步框架能带来理能力上的提升,支持更多的请求和链接,这是为啥呢?不太理解。
    相比较而言,如果换成使用线程池来发起多个 http 也用 future 来接受结果,到底提升在哪呢?
    异步请求 http 的时候也是用的线程呀,这个线程与线程池里的线程有啥区别吗?凭啥更好呢?
    20 条回复    2021-05-12 18:51:27 +08:00
    ch2
        1
    ch2  
       2021-04-28 18:13:16 +08:00   1
    异步的协程不是真正的线程,你可以理解为开成千上万个对机器性能的压力都是毛毛雨
    多线程是可以达到一样的效果,但是额外的 CPU 跟内存开销大了很多
    并且多线程还容易出 bug 不好调试,代码逻辑更是无端变复杂了很多
    改成异步之后你单个线程一秒钟就可以发一千个请求毫无压力,直接一个就能顶一千个线程
    你还可以开 n 个线程,每个线程都用异步
    buff 可以叠加何乐而不为?
    yumenawei
        2
    yumenawei  
    OP
       2021-04-28 20:20:11 +08:00
    @ch2 #1 老哥,你好。
    Java 是没有协程的,只有线程。你说的协程应该是其他语言的。
    所以异步里应该也是用的线程。
    没有啥特别的优势。
    ikas
        3
    ikas  
       2021-04-28 21:30:28 +08:00   1
    http 异步是让你减少 cpu 的浪费,再等待结果的过程中,可以继续执行其他的调用
    BBCCBB
        4
    BBCCBB  
       2021-04-28 21:57:46 +08:00   1
    future.get 还是会阻塞住, 完全异步应该是要针对 future 加个 listener 回调, 在回调里处理. 可以用 reactor 这种写法. 或者 CompletableFuture..
    micean
        5
    micean  
       2021-04-28 22:23:19 +08:00   1
    vertx 的 httpclient 同样也是使用线程池,future.get 应该是 java.util.concurrent 包里的
    异步只是为了提醒和帮助你更好的使用非阻塞,减少线程数。
    大多数实际场景异步同步的性能差距并不太明显。
    cloud107202
        6
    cloud107202  
       2021-04-28 23:21:12 +08:00   1
    使用异步的服务伸缩性更好,比如 spring boot 同步的 web 需要预估请求量来配置线程池的最小最大值。
    最大值配小了遇到高峰请求服务不过来,高峰过了又在 pool 里空等
    kaneg
        7
    kaneg  
       2021-04-28 23:49:10 +08:00   1
    单纯的异步用线程池就可以,但要极大地提高性能,底层的 http 客户端应该要用 NIO 才行。
    ipwx
        8
    ipwx  
       2021-04-29 00:00:09 +08:00   1
    1. 用 future.get 就错了。
    2. t/772976#reply28
    wqhui
        9
    wqhui  
       2021-04-29 09:27:08 +08:00   1
    http 请求发送完成到接到响应这过程是主要耗时,在你用 get 阻塞之前还能多发几个 http 请求,同时等待响应。如果说线程池内的线程表现更好,有两个可能,一是响应是靠回调的,就是三楼说的 listener 写法,不需要阻塞(按你自己的阻塞写法,理论上是会有时间浪费在那);二是线程复用
    gaius
        10
    gaius  
       2021-04-29 09:41:24 +08:00   1
    用 webflux 的 webclient
    yumenawei
        11
    yumenawei  
    OP
       2021-04-29 11:24:21 +08:00
    @ikas #3 感觉只是一部分原因,结果的获取仍然需要有人去执行,这个地方仍然会用 cpu

    @BBCCBB #4 这个地方我们可能没有处理的太好,后面研究下

    @micean #5 我往下看了下,vertx 好像用了 netty 做了客户端的 nio,不大确定,还在看,老哥了解吗?

    @cloud107202 #6 那这个也不是伸缩性好吧?而是性能和处理效果更高?

    @kaneg #7 看了下,好像底层是用的 netty 做的客户端 nio,还在看,感谢提供思路

    @ipwx #8 感谢分享。因为服务需要调用的结果,所以用的 future.get ,请问正确的用法是?

    @wqhui #9 感谢,应该是底层用了客户端的 nio 来处理请求,提升性能

    @gaius #10 老哥,应该是与框架没太大关系,我想了解的是上了这个框架,为啥性能和效果更高。
    BBCCBB
        12
    BBCCBB  
       2021-04-29 14:08:32 +08:00
    为啥性能更好这个..


    可以参考传统的网络编程, 一个线程处理一个连接, 大部分时间都没有读写, 线程经常在睡眠和睡眠状态来回切换, 大量时间和 cpu 花在 context swtich 上,

    而 nio 这种. 一个或几个线程就能处理大量连接, context switch 很少,能把 cpu 利用起来
    unco020511
        13
    unco020511  
       2021-04-29 16:06:05 +08:00
    jvm 没有协程,所以基于 jvm 语言的协程 api 都是用的线程
    7075
        14
    7075  
       2021-04-29 17:41:27 +08:00
    可以参考一下 icop 模型和 epoll 模型,
    异步的本质就是不浪费机器资源在阻塞上。
    micean
        15
    micean  
       2021-04-29 21:42:08 +08:00
    @yumenawei

    vertx 本来就是 netty pro,无论是线程还是 Buffer 都是对 netty 的封装,Vertical 和 Context 那一套保证线程安全的东西才是属于 vertx 的
    passerbytiny
        16
    passerbytiny  
       2021-04-30 09:54:46 +08:00 via Android
    异步的重点不是线程池 /协程( Java 只有线程池没有协程),而是多任务切换。

    你这个总是使用 future.get ,等同于同步调用(虽然比常规同步会好那么一丁点),并不能提高并发能力。要用到 listener 才能发挥异步的真正实力。
    ikas
        17
    ikas  
       2021-04-30 16:56:37 +08:00
    @yumenawei 你要把异步 io 与线程池 /线程这些分开去想 .假设你用异步 io 的 httpclient,那么你可以在一个线程中调用这个 client10 次,然后在这个线程中使用 get 等待.如果你用同步 io 的 httpclient,那么你要实现这样,就是要开 10 个线程,那如果更多呢
    yumenawei
        18
    yumenawei  
    OP
       2021-05-06 16:12:55 +08:00
    @micean #15 感谢指导。
    @passerbytiny #16 嗯嗯,还有就是请求用了 nio,不用一个线程一直等待结果。
    @BBCCBB #12 当初没想到客户端也可以用 nio
    @ikas #17 是,我被异步这个东西限制住了思考
    CantSee
        19
    CantSee  
       2021-05-12 18:20:51 +08:00
    通过线程池进行多线程调用时,业务代码是并行的,但是在 future.get 是阻塞的吧()
    yumenawei
        20
    yumenawei  
    OP
       2021-05-12 18:51:27 +08:00
    @CantSee #19 对,一直阻塞直到超时或者有结果返回。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2617 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 12:56 PVG 20:56 LAX 04:56 JFK 07:56
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86