优化开票任务Demo开发(章节2)-CSDN博客(书接上回)
在这个项目里,分片就一个意义:把一个跑得很慢的串行大任务,拆成多个能并行的独立小任务,压榨多核 + 缩短整体耗时。
简单一句话:不分片只能在一个线程上跑,分片后可以在heavyPool中的多个线程分别跑
废话解释看不懂可看ai讲的不是我讲的:
具体对着 ImprovedInvoiceService 看:
-
不分片是什么样:
LegacyInvoiceService是单线程 for 循环扫全量账户,一个账户模拟ioMsPerAccount耗时,N个账户总耗时就是N × 单次耗时,线性增长,1 万账户直接卡死,还占着线程不放,后面的充值/查询全被队头阻塞。 -
分片后是什么样:先
quotaCache.snapshotKeys()拿到 N 个 key,按chunkSize切成ceil(N/chunkSize)个subList,每个chunk包成一个CompletableFuture丢回heavyPool并行跑,最后join聚合。理想耗时从N × t降到(N/并行度) × t,日志里那句"处理 N 个账户,并行耗时 X ms"就是为了证明这个。 -
为什么这里能分片:前提是
QuotaCache用了ConcurrentHashMap做快照。读cache.get()是线程安全的、无锁分段的,多个分片线程同时读不会打架,也不用每次查库。如果还是直接扫 DB,分片只会把 DB 打爆,没有意义。 -
为什么还要配隔离池:分片会瞬间产生大量子任务,如果和普通业务共用一个池,快池会被开票分片占满。所以分片只在
heavyPool内部消化,fastPool照常跑短任务,互不抢占。
一句话:分片不是为了省线程、也不是为了建池,而是用"任务并行度"换"时间",前提是数据可并发读、执行有隔离池兜底。