陪玩系統原始碼利用介面非同步呼叫,減少介面耗時

雲豹科技程式設計師發表於2021-11-19
隨著陪玩系統原始碼中業務功能的發展,底層資料量越來越大,業務邏輯也日趨複雜化,某些介面耗時也越來越長,這時候介面就需要進行效能優化了,當然效能優化主要跟陪玩系統原始碼業務相關涉及改造點可能各不相同,這裡就來介紹非同步呼叫多個介面減少響應時間。

適用條件

  • 呼叫多個獨立的介面,介面間無相互依賴關係
  • 非耗時最大的介面占總耗時比重較大

優化前呼叫方式

優化前的陪玩系統原始碼按照順序呼叫方式:
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DemoTest {
    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        int processA = new InterfaceA().process();
        int processB = new InterfaceB().process();
        int result = processA + processB;
        log.info("執行結果:{} 耗時:{}", result, System.currentTimeMillis() - beginTime);
    }
    @Slf4j
    public final static class InterfaceA {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceA.process Exception");
            }
            log.info("執行介面InterfaceA.process 耗時:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
    @Slf4j
    public final static class InterfaceB {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceB.process Exception");
            }
            log.info("執行介面InterfaceB.process 耗時:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}
執行結果:
21:40:17.603 [main] INFO DemoTest$InterfaceA - 執行介面InterfaceA.process 耗時:2002ms
21:40:19.612 [main] INFO DemoTest$InterfaceB - 執行介面InterfaceB.process 耗時:2001ms
21:40:19.613 [main] INFO DemoTest - 執行結果:2 耗時:4018

優化後呼叫方式

優化後的陪玩系統原始碼按照非同步呼叫方式:
import cn.hutool.core.thread.ThreadFactoryBuilder;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Slf4j
public class DemoTest {
    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(
            5,
            5,
            60,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(1000),
            ThreadFactoryBuilder.create().setNamePrefix("執行緒名稱-").build()
    );
    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        List<Future<Integer>> futures = new ArrayList<>(2);
        List<Integer> results = new ArrayList<>(2);
        futures.add(pool.submit(() -> new InterfaceA().process()));
        futures.add(pool.submit(() -> new InterfaceB().process()));
        for (Future<Integer> item : futures) {
            results.add(item.get());
        }
        
        int result = results.get(0) + results.get(1);
        log.info("執行結果:{} 耗時:{}", result, System.currentTimeMillis() - beginTime);
    }
    @Slf4j
    public final static class InterfaceA {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceA.process Exception");
            }
            log.info("執行介面InterfaceA.process 耗時:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
    @Slf4j
    public final static class InterfaceB {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceB.process Exception");
            }
            log.info("執行介面InterfaceB.process 耗時:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}
執行結果:
22:03:43.180 [執行緒名稱-1] INFO DemoTest$InterfaceB - 執行介面InterfaceB.process 耗時:2004ms
22:03:43.180 [執行緒名稱-0] INFO DemoTest$InterfaceA - 執行介面InterfaceA.process 耗時:2004ms
22:03:43.190 [main] INFO DemoTest - 執行結果:2 耗時:2020

強大的CompletableFuture JDK1.8

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
@Slf4j
public class DemoTest {
    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        CompletableFuture<Integer> interfaceFuturesA = CompletableFuture.supplyAsync(() -> new InterfaceA().process());
        CompletableFuture<Integer> interfaceFuturesB = CompletableFuture.supplyAsync(() -> new InterfaceB().process());
        CompletableFuture<List<Integer>> future = CompletableFuture
                .allOf(interfaceFuturesA, interfaceFuturesB)
                .thenApply((none) -> {
                    List<Integer> dataList = new ArrayList<>(2);
                    try {
                        dataList.add(interfaceFuturesA.get());
                        dataList.add(interfaceFuturesB.get());
                    } catch (Exception e) {
                        log.error("執行異常");
                    }
                    return dataList;
                }).exceptionally(e -> Lists.newArrayList());
        int result = future.get().get(0) + future.get().get(1);
        log.info("執行結果:{} 耗時:{}", result, System.currentTimeMillis() - beginTime);
    }
    @Slf4j
    public final static class InterfaceA {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceA.process Exception");
            }
            log.info("執行介面InterfaceA.process 耗時:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
    @Slf4j
    public final static class InterfaceB {
        Integer result = 1;
        public int process() {
            long beginTime = System.currentTimeMillis();
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("InterfaceB.process Exception");
            }
            log.info("執行介面InterfaceB.process 耗時:{}ms", System.currentTimeMillis() - beginTime);
            return result;
        }
    }
}
執行結果:
22:31:44.822 [ForkJoinPool.commonPool-worker-5] INFO DemoTest$InterfaceB - 執行介面InterfaceB.process 耗時:2005ms
22:31:44.822 [ForkJoinPool.commonPool-worker-3] INFO DemoTest$InterfaceA - 執行介面InterfaceA.process 耗時:2002ms
22:31:44.831 [main] INFO DemoTest - 執行結果:2 耗時:2027

優化時注意點

  • 在陪玩系統原始碼進行介面非同步呼叫時,可以使用執行緒池防止記憶體溢位風險
  • 陪玩系統原始碼的執行結果容器可自行根據需要設定
  • 介面粒度可根據實際業務情況組合和拆分
本文轉載自網路,轉載僅為分享乾貨知識,如有侵權歡迎聯絡雲豹科技進行刪除處理


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69996194/viewspace-2843152/,如需轉載,請註明出處,否則將追究法律責任。

相關文章