记录下并行优化时的一个问题

    最近在做模块性能优化时,尝试将请求外部模块和操作数据库这种耗时操作又非前后关联的动作改为并行,用到了CompletableFuture.runAsync,遍历复杂集合时修改为parallelStream;

    实际上parallelStream和CompletableFuture.runAsync的并行都是使用了Fork/join的线程池来处理,可以参考http://blog.dyngr.com/blog/2016/09/15/java-forkjoinpool-internals/, 既然是用这个线程池,那么我们肯定会面临2个问题:
1.会有线程上下文切换,处理线程到fork/join池中线程的切换,是否有参数必须传递过去;
2.使用的fork/join池是jvm全局共用,所有并行流调用和所有的CompletableFuture.runAsync都会用到,大小是cpu个数,如果竞争,反而会降低性能(所以很多链接都会说,cpu密集型适合用并行流,比如不少实测也是计算型测试,性能确实好,但是实际上大多数业务都不是cpu密集型任务)。

对第一个问题可能的影响,以我们业务为例,ServiceComb有个上下文CseContext,在rpc调用时是塞到x-cse-context的http头里的,线程切换时如果不设置则不会携带到下游模块导致报错,解决方法也简单:

InvocationContext context = ContextUtils.getInvocationContext();

然后在并行流中开始遍历前或者CompletableFuture.runAsync或者thenRunAsync方法首先设置一下上下文

ContextUtils.setInvocationContext(context);

对第二个问题,对并行流和CompletableFuture.runAsync的处理也是不一样的,并行流处理可参考 http://www.importnew.com/16801.html 

ForkJoinTask<?> task = forkJoinPool.submit(() -> conditions.parallelStream().forEach(condition ->
{
   xx
}));
xx;
task.join();

对CompletableFuture.runAsync 则是传入自定义的ExecutorService对象来防止系统限制的大小

final AtomicInteger threadId = new AtomicInteger(0);

private ExecutorService executor =
    new ThreadPoolExecutor(100, 100, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(100),
        r -> new Thread(r, "rule-parallel-thread-" + threadId.getAndIncrement()));

调用时

InvocationContext context = ContextUtils.getInvocationContext();
CompletableFuture.runAsync(() ->
{
    ContextUtils.setInvocationContext(context);
   xxx
}, executor).thenRunAsync(() ->
{
    ContextUtils.setInvocationContext(context);
    xxx
}, executor).thenRunAsync(() ->
{
    ContextUtils.setInvocationContext(context);
    xxx
}, executor).join();

坐等性能测试结果,调整线程池大小

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值