並行最適化時の問題を記録します.


最近モジュールの性能最適化を行う際に、外部モジュールと操作データベースを要求するような時間つぶし操作と前後の関連ではない動作を並行に変えてみました.Compleable Future.runAsyncを使用して、複雑な集合を遍歴した時にパラルStereamに変更しました.
    実際にはparallel StreamとCompleable Future.runAsyncの並列はFork/joinのスレッド池を使って処理していますので、参考にしてください.http://blog.dyngr.com/blog/2016/09/15/java-forkjoinpool-internals/を選択します. このスレッドを使うと、必ず二つの問題に直面します.2.使用しているfork/joinプールはjvmグローバル共用で、すべての並列ストリーム呼び出しとすべてのCompleable Future.runAryncはいずれも使用します.サイズはcpuの個数です.競争すれば、逆に性能を低下させます.(だから多くのリンクでは、cpu密集型は並列流に適していると言われています.例えば、多くの実測も計算型テストで、性能は確かに良いですが、実際にはほとんどの業務はcpu密集型の仕事ではありません).
第一の問題に対して可能な影響は、私達の業務を例にとって、ServiceCombにはコンテキストCseContectがあり、rpc呼び出し時にx-cse-contextのhttpヘッダに詰め込まれています.スレッド切り替え時に設定しないと下流モジュールに持ち込まれなくなりエラーが発生します.解決方法も簡単です.
InvocationContext context = ContextUtils.getInvocationContext();
その後、並列ストリームで巡回開始前またはCompleable Future.runAsyncまたはthenRunAsync方法は、まずコンテキストを設定します.
ContextUtils.setInvocationContext(context);
第二の問題については、並列ストリームとCompleable Future.runAsyncの処理も違っています.並列ストリーム処理は参照できます. http://www.importnew.com/16801.html 
ForkJoinTask> task = forkJoinPool.submit(() -> conditions.parallelStream().forEach(condition ->
{
   xx
}));
xx;
task.join();
Compleable Future.runAsyncには、システム制限の大きさを防ぐために、カスタムExectorServiceオブジェクトが導入されます.
final AtomicInteger threadId = new AtomicInteger(0);

private ExecutorService executor =
    new ThreadPoolExecutor(100, 100, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(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();
シート性能試験結果、スレッドサイズを調整します.