时长:大小11.55M
作者回复: 人工置顶🔝
作者回复: 👍👍👍
作者回复: 太多的线程会造成频繁的cpu上下文切换,你可以想象一下,假设你的小公司只有8台电脑,你雇8个程序员一直不停的工作显然是效率最高的。考虑到程序员要休息不可能连轴转,雇佣24个人,每天三班倒,效率也还行。
但是,你要雇佣10000个人,他们还是只能用这8台电脑,大部分时间不都浪费在换人、交接工作上了吗?
作者回复: 👍👍👍
线程就是为了能自动分配CPU时间片而生的。
作者回复: 首先,你要理解,为什么请求多了程序会变慢这个事儿。
计算的资源,比如说CPU、磁盘IO,它的处理能力是恒定的,都不会因为请求量大而“变慢”。
比如说CPU执行一次加法,任何情况下耗时都是差不多的。
我们所看到的请求量大“系统变慢”的现象,一定是因为某一种资源忙,达到了瓶颈。比如说,一个单核CPU,每做一次加法需要0.1秒,那它每秒最多做10次加法。
一下子100个程序同时都来请求CPU做一次加法,这个CPU就需要10秒才能算完。对于这个CPU,它并没变慢,仍然是每秒做10次加法。
但是对于某一个请求CPU的程序来说,它看到的现象是,我让CPU做了一次加法,它八秒才做完,看起来就是“变慢”了。
所以,程序变慢一定是因为某一个资源忙,遇到了瓶颈。同步程序因为线程数量的限制,它的瓶颈往往是线程数量。并不能发挥服务器的全部处理能力。异步程序不需要那么多线程,所以可以发挥出服务器的全部处理能力,直到把CPU或者磁盘IO打满,所以要快得多。
作者回复: 👍👍👍
作者回复: 总结的非常好!
有一点需要改进一下,转账服务的实现中,异常处理的部分,还是需要先检查再补偿,否则有可能出现重复补偿的情况。
作者回复: 性能上没有区别。
区别是代码结构更清晰简单,易于维护。
作者回复: 这里说一下我的理解:
CompletableFuture还不能等完全同于ForkJoin。
可以简单的理解为
CompletableFuture.then() 等于 Fork
CompletableFuture.get() 等于 Join
但不是所有场景下,CompletableFuture都需要用get()结束的。也就是说,有时候是不需要调用阻塞的get()方法的。
另外,虽然CompletableFuture 默认使用 ForkJoinPool,但你完全可以给它提供一个自定义的执行器。
作者回复: 结合Netty或者NIO,是可以做到全异步的,不需要线程在阻塞等待响应。
作者回复: 第一个问题,转入转出这两个操作不需要串行,是可以并行的。甚至执行顺序都没什么要求。我们唯一要保证的是这两个操作在一个事务中执行, “要么都成功,要么都失败”,就可以了。
你这个场景是在调用方(转账服务)异步,而服务提供方(账户服务)还是同步服务的情况下,才会出现。
你仔细看一下我们的异步设计,服务提供方提供的也是异步服务,那调用账户服务也是一瞬间就完成了,这样就不会出现你说的“几万个请求对象在CompletableFuture内部线程池内部还是排队”的情况了。
作者回复: 实际生产系统中的转账服务,大部分都是异步的。