V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
RRRSSS
V2EX  ›  程序员

Java 异步问题

  •  1
     
  •   RRRSSS · 2020-03-31 12:35:18 +08:00 · 3492 次点击
    这是一个创建于 1477 天前的主题,其中的信息可能已经有所发展或是发生改变。

    现在我负责一个服务,主要是融合功能,根据传过来的参数,来调用上游的 A 、B 、C 三个 dubbo 服务,三个服务相互没有依赖,超时就丢弃,无所谓,然后拿到数据把他们 merge 一下,返回给下游。

    这个时候,A B C 三个服务 dubbo 超时设置的都是 200ms,我想异步调用他们,就使用 CompletableFuture,然后自定线程池处理的。但有人说高 IO 不要用 CompletableFuture,那怎么做这个异步呢?

    求解

    第 1 条附言  ·  2020-03-31 20:44:48 +08:00
    看了大家的留言,自己再研究了一下,也问了公司同事,应该是这样的:

    CompletableFuture 默认使用线程池是 ForkJoinPool,而 ForkJoinPool 默认的线程数是 CPU 核数 - 1,擅长处理 CPU 密集型任务,而 IO 密集型任务需要自己合理配置的线程池(至于怎么设置,有经验问题,也可以压测慢慢调整,这个属于 JVM 调优部分)。
    20 条回复    2020-04-01 10:28:33 +08:00
    127000
        1
    127000  
       2020-03-31 12:47:51 +08:00
    RRRSSS
        2
    RRRSSS  
    OP
       2020-03-31 12:50:10 +08:00
    @127000 这个我看到了,不过需要 3 个上游都改接口,沟通成本太大,所以想着自己这边做。
    Foredoomed
        3
    Foredoomed  
       2020-03-31 13:24:41 +08:00
    自己定义个线程池, 然后用 CompletableFuture.runAsync(Runnable, Executor)
    RRRSSS
        4
    RRRSSS  
    OP
       2020-03-31 14:13:21 +08:00
    @Foredoomed 现在就是这么做的,关键是线程池定义多大,异步我了解得不多,我看网上说的是 CompletableFuture 适合 CPU 密集型任务,但是我这个是 高 IO 任务。
    ayavvv
        5
    ayavvv  
       2020-03-31 14:20:47 +08:00
    为什么 CompletableFuture 适合 CPU 密集型任务不适合高 IO 任务?
    直接用 Future 行不行?
    Jafee
        6
    Jafee  
       2020-03-31 14:21:13 +08:00
    不如先找找 CompletableFuture 不适合 I/O 操作的原因再排除 CompletableFuture 。(个人能力有限,没想到是什么原因导致的这个规则)

    “如果你并行的工作单元还涉及等待 I/O 的操作(包括网络连接等待),那么使用 CompletableFuture 灵活性更好。(与并行流相比较)” —— 《 Java 8 实战》
    Foredoomed
        7
    Foredoomed  
       2020-03-31 14:40:26 +08:00
    线程池设个最大线程数就行了,不用太精确。你只要做压力测试就行了,网上又不是都对的。
    optional
        8
    optional  
       2020-03-31 14:45:37 +08:00
    同步 call 都挺蛋疼,只能用线程池,可能线程池可以开大一点。
    yqsas
        9
    yqsas  
       2020-03-31 14:47:05 +08:00 via iPhone
    Aresxue
        10
    Aresxue  
       2020-03-31 14:50:15 +08:00
    CompletableFuture 是最佳方案,dubbo 自己的异步调用就支持。话说 IO 多才更适合使用 CompletableFuture, 能让 CPU 更充分利用,谁说不利于高 IO 的?我能想到的只是高 IO 对系统危害比较大, 以及失败及异常处理较为复杂。
    NeinChn
        11
    NeinChn  
       2020-03-31 14:55:06 +08:00
    记错了吧,绝大部分情况下请不要开多线程跑 CPU 密集型任务
    除非是单机就你一个请求在跑的场景,比如客户端,单机训练
    IO 操作只要是可以并行的,建议都并行跑.
    wysnylc
        12
    wysnylc  
       2020-03-31 14:58:21 +08:00
    @Jafee #6 计算密集型时设定线程池为虚拟核心数即可,IO 密集型则根据实际任务决定
    CompletableFuture 和 parallelStream 一样默认使用 ForkJoinPool 的线程池,ForkJoinPool 默认线程数是虚拟核心数
    所以 CompletableFuture 默认适合计算密集型,需要 IO 密集型则要自己定义线程池
    说 CompletableFuture 不适应 IO 密集型的要么是个半吊子,要么故意说一半藏一半误导别人,非蠢即坏
    nickchenyx
        13
    nickchenyx  
       2020-03-31 14:59:32 +08:00
    基本上还是一个 CompletableFuture + 自定义线程池解决这种问题的,不过这也有缺陷。

    Q:A 、B 、C 三个接口耗时不同,例如 C 不稳定,rt 比 A 、B 高很多,这时候就会因为 C 的 rt 影响整体的吞吐
    A: 线程池隔离,使用独立的线程池资源,隔离 C 的访问调用
    Q:C 的访问隔离了之后,如何处理 C 访问过慢的问题呢
    A:抛弃策略处理,或者使用 熔断 + FallbackFactory 构造默认返回

    说到这里基本就是 hystrix 做的事情了,各种熔断时间配置,资源隔离的颗粒度,这都是可以看 hystrix 的文档可以看到的。

    (有人说高 IO 不要用 CompletableFuture 这个问题,我觉得可能是因为底层还是使用 ForkJoin 的方式在处理任务,高延迟的任务会影响整理进度吧? 疯狂猜测
    LeeSeoung
        14
    LeeSeoung  
       2020-03-31 15:05:30 +08:00
    CompletableFuture 、CompositeFuture 。。= =我一度以为我记错了,原来这两个不一样的。。偏题了
    xiaoidea
        15
    xiaoidea  
       2020-03-31 17:28:58 +08:00
    我就是开线程池的
    bringyou
        16
    bringyou  
       2020-03-31 17:44:28 +08:00
    估计是因为 CompletableFuture 的 runAsync 等不带线程池入参的方法,使用的是默认的 forkJoinPool,这个线程池的线程数量是固定的 cpu 数目,且是整个 JVM 共享的,不太适合跑高 IO 应用。
    建议使用带线程池入参的方法,传进去自定义线程池。这个自定义线程池的最大线程数可以设置高一点。举个例子,[kotlin 里面跑 IO 协程的调度器,设置的最少 64 个线程]( https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/jvm/src/scheduling/Dispatcher.kt#L17)
    gaius
        17
    gaius  
       2020-03-31 21:40:19 +08:00 via Android
    可以指定自定义的线程池
    renyijiu
        18
    renyijiu  
       2020-03-31 21:46:43 +08:00
    制定一个线程池就好了,常用的 io 型数量可以 cpu * 2 + 1
    1424659514
        19
    1424659514  
       2020-04-01 08:43:42 +08:00
    CompletableFuture 指定一个线程池就可以了, 用这个方法

    runAsync(Runnable runnable,Executor executor)
    sagaxu
        20
    sagaxu  
       2020-04-01 10:28:33 +08:00 via Android
    CompletableFuture 用 ForkJoinPool 线程数少不擅长 IO 密集型?正好相反,所有擅长 IO 密集型的解决方案,核心思想之一就是减少线程数。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5934 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 757ms · UTC 06:06 · PVG 14:06 · LAX 23:06 · JFK 02:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.