国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

閱文集團(tuán)旗下哪個(gè)網(wǎng)站做的最好seo培訓(xùn)一對(duì)一

閱文集團(tuán)旗下哪個(gè)網(wǎng)站做的最好,seo培訓(xùn)一對(duì)一,河南網(wǎng)站建設(shè)首選公司,微信做單子的網(wǎng)站源碼背景 今天在開發(fā)質(zhì)量平臺(tái)時(shí)需要獲取某些數(shù)據(jù),要請(qǐng)求公司某個(gè)工程的OpenAPI接口A。此接口為返回通用數(shù)據(jù)的接口,且接口本身的RT都在2~3秒之間。使用該接口,需要進(jìn)行兩次循環(huán)獲取,然后對(duì)返回?cái)?shù)據(jù)進(jìn)行處理組裝&#xff0…

背景

今天在開發(fā)質(zhì)量平臺(tái)時(shí)需要獲取某些數(shù)據(jù),要請(qǐng)求公司某個(gè)工程的OpenAPI接口A。此接口為返回通用數(shù)據(jù)的接口,且接口本身的RT都在2~3秒之間。使用該接口,需要進(jìn)行兩次循環(huán)獲取,然后對(duì)返回?cái)?shù)據(jù)進(jìn)行處理組裝,才能得到我這邊工程需要的數(shù)據(jù)。

在最開始的時(shí)候,我天真的寫了兩層循環(huán),外層循環(huán)為一星期的每一天,內(nèi)層循環(huán)為選取的幾個(gè)版本號(hào)。結(jié)果發(fā)現(xiàn)整個(gè)請(qǐng)求過程(請(qǐng)求接口B和C獲取版本相關(guān)數(shù)據(jù)->兩層循環(huán)請(qǐng)求接口A->數(shù)據(jù)過濾篩選->數(shù)據(jù)組裝排序)下來,響應(yīng)時(shí)間來到了恐怖的2分鐘(🤔要被領(lǐng)導(dǎo)罵死了)

同時(shí)數(shù)據(jù)又都要實(shí)時(shí)獲取,無(wú)法使用定時(shí)任務(wù)和緩存的方式

解決思路

將for循環(huán)改為多線程的方式進(jìn)行執(zhí)行,一種常用的方法是使用Executor框架

package com.xxx.xxx;...
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class Main {public static void main(String[] args) {// 模擬數(shù)據(jù)庫(kù)中的100條數(shù)據(jù);List list = new ArrayList();for (int i = 0; i < 100; i++) {list.add(i);}//Executors創(chuàng)建線程池new固定的10個(gè)線程ExecutorService taskExecutor = Executors.newCachedThreadPool();final CountDownLatch latch = new CountDownLatch(list.size());//用于判斷所有的線程是否結(jié)束System.out.println("個(gè)數(shù)==" + list.size());for (int m = 0; m < list.size(); m++) {final int n = m;//內(nèi)部類里m不能直接用,所以賦值給nRunnable run = new Runnable() {public void run() {try {System.out.println("我在執(zhí)行=" + n);} finally {latch.countDown(); //每次調(diào)用CountDown(),計(jì)數(shù)減1}}};taskExecutor.execute(run);//開啟線程執(zhí)行池中的任務(wù)。還有一個(gè)方法submit也可以做到,它的功能是提交指定的任務(wù)去執(zhí)行并且返回Future對(duì)象,即執(zhí)行的結(jié)果}try {//等待所有線程執(zhí)行完畢latch.await();//主程序執(zhí)行到await()函數(shù)會(huì)阻塞等待線程的執(zhí)行,直到計(jì)數(shù)為0} catch (InterruptedException e) {e.printStackTrace();}taskExecutor.shutdown();//關(guān)閉線程池//所有線程執(zhí)行完畢,執(zhí)行主線程}}

注意:在使用多線程時(shí),需要注意線程安全問題,如果程序中使用了共享變量,需要進(jìn)行同步處理。

業(yè)務(wù)使用

@Override
public List<JSONObject> getBoomCrash(String appId, String androidEventType, String OS, Set<String> appVersionSet, List<Map<String, Long>> timeScope) throws URISyntaxException, IOException {Map<String, String[]> versionTagMap = new HashMap<>();// 首先獲取版本信息。業(yè)務(wù)代碼,省略....// 第一步先獲取傳入版本所有的crash數(shù)據(jù),并過濾掉版本首次出現(xiàn)的。業(yè)務(wù)代碼,省略List<BoomCrashDataVo> boomCrashDataList = ...// 第二步,獲取所有版本和UV【以昨日數(shù)據(jù)為標(biāo)準(zhǔn),結(jié)果是UV倒序排列】。業(yè)務(wù)代碼,省略List<CrashVersionUvDataVo> versionUvResult = ...// 第三步,判斷當(dāng)前版本的上一個(gè)全量版本。業(yè)務(wù)代碼,省略String lastVersion = ...List versionList = new ArrayList();for (String key : appVersionSet) {versionList.add(key);}versionList.add(lastVersion);String versionListstr = StringUtils.join(versionList, ",");List<JSONObject> boomCrashDataListNew = new ArrayList<>();// 第四步,循環(huán)判斷獲取某個(gè)issue數(shù)據(jù)的數(shù)量情況// Executors創(chuàng)建線程池new固定的10個(gè)線程ExecutorService taskExecutor = Executors.newCachedThreadPool();final CountDownLatch latch = new CountDownLatch(boomCrashDataList.size());//用于判斷所有的線程是否結(jié)束for (BoomCrashDataVo boomCrashData : boomCrashDataList) {Runnable run = new Runnable() {public void run() {try {// 這里是業(yè)務(wù)代碼...} finally {latch.countDown(); //每次調(diào)用CountDown(),計(jì)數(shù)減1}}};taskExecutor.execute(run);}try {//等待所有線程執(zhí)行完畢latch.await(); //主程序執(zhí)行到await()函數(shù)會(huì)阻塞等待線程的執(zhí)行,直到計(jì)數(shù)為0} catch (InterruptedException e) {e.printStackTrace();}taskExecutor.shutdown();// 按照TOP進(jìn)行正序排序Collections.sort(boomCrashDataListNew, new Comparator<JSONObject>() {@Overridepublic int compare(JSONObject v1, JSONObject v2) {Integer uv1 = v1.getIntValue("topNumber");Integer uv2 = v2.getIntValue("topNumber");return uv1.compareTo(uv2);}});return boomCrashDataListNew;
}

改造成果

響應(yīng)時(shí)間降到了20~30秒,和業(yè)務(wù)溝通在可接受范圍內(nèi)。同時(shí),前端我修改成了在請(qǐng)求數(shù)據(jù)過程中顯示加載組件(參考antd的),這樣就不會(huì)顯示太過突兀,提升用戶使用體驗(yàn)。

深入學(xué)習(xí)

執(zhí)行器服務(wù)

java.util.concurrent.ExecutorService 接口表示一個(gè)異步執(zhí)行機(jī)制,使我們能夠在后臺(tái)執(zhí)行任務(wù)。因此一個(gè) ExecutorService 很類似于一個(gè)線程池。實(shí)際上,存在于 java.util.concurrent 包里的 ExecutorService 實(shí)現(xiàn)就是一個(gè)線程池實(shí)現(xiàn)。

ExecutorService executorService = Executors.newFixedThreadPool(10);executorService.execute(new Runnable() {public void run() {System.out.println("Asynchronous task");}});
executorService.shutdown();

首先使用 newFixedThreadPool() 工廠方法創(chuàng)建一個(gè) ExecutorService。這里創(chuàng)建了一個(gè)十個(gè)線程執(zhí)行任務(wù)的線程池。然后,將一個(gè) Runnable 接口的匿名實(shí)現(xiàn)類傳遞給 execute() 方法。這將導(dǎo)致 ExecutorService 中的某個(gè)線程執(zhí)行該 Runnable。

任務(wù)委派

下圖說明了一個(gè)線程是如何將一個(gè)任務(wù)委托給一個(gè) ExecutorService 去異步執(zhí)行的:

image.png

一旦該線程將任務(wù)委派給 ExecutorService,該線程將繼續(xù)它自己的執(zhí)行,獨(dú)立于該任務(wù)的執(zhí)行。

ExecutorService實(shí)現(xiàn).

既然 ExecutorService 是個(gè)接口,如果你想用它的話就得去使用它的實(shí)現(xiàn)類之一。 java.util.concurrent 包提供了 ExecutorService 接口的以下實(shí)現(xiàn)類:

ThreadPoolExecutor
ScheduledThreadPoolExecutor

ExecutorService使用

有幾種不同的方式來將任務(wù)委托給 ExecutorService 去執(zhí)行:

  1. execute(Runnable)
  2. submit(Runnable)
  3. submit(Callable)
  4. invokeAny(…)
  5. invokeAll(…)

execute(Runnable)

execute(Runnable) 方法要求一個(gè) java.lang.Runnable 對(duì)象,然后對(duì)它進(jìn)行異步執(zhí)行。以下是使用 ExecutorService 執(zhí)行一個(gè) Runnable 的示例:

ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {public void run() {System.out.println("Asynchronous task");} 
});
executorService.shutdown();

沒有辦法得知被執(zhí)行的 Runnable 的執(zhí)行結(jié)果。如果有需要的話你得使用一個(gè) Callable(以下將做介紹)。

submit(Runnable)

submit(Runnable) 方法也要求一個(gè) Runnable 實(shí)現(xiàn)類,但它返回一個(gè) Future 對(duì)象。這個(gè)Future 對(duì)象可以用來檢查 Runnable 是否已經(jīng)執(zhí)行完畢。
以下是 ExecutorService submit() 示例:

Future future = executorService.submit(new Runnable() {public void run() {System.out.println("Asynchronous task");}
});
future.get(); //returns null if the task has finished correctly

submit(Callable)

submit(Callable) 方法類似于 submit(Runnable) 方法,除了它所要求的參數(shù)類型之外。
Callable 實(shí)例除了它的 call() 方法能夠返回一個(gè)結(jié)果之外和一個(gè) Runnable 很相像。

Runnable.run() 不能夠返回一個(gè)結(jié)果。Callable 的結(jié)果可以通過 submit(Callable) 方法返回的 Future 對(duì)象進(jìn)行獲取。以下是一個(gè)

ExecutorService Callable 示例:

Future future = executorService.submit(new Callable(){public Object call() throws Exception {System.out.println("Asynchronous Callable");return "Callable Result";}
});
System.out.println("future.get() = " + future.get());// 輸出
Asynchronous Callable  
future.get() = Callable Result

invokeAny()

invokeAny() 方法要求一系列的 Callable 或者其子接口的實(shí)例對(duì)象。調(diào)用這個(gè)方法并不會(huì)返回一個(gè) Future,但它返回其中一個(gè) Callable 對(duì)象的結(jié)果。無(wú)法保證返回的是哪個(gè) Callable 的結(jié)果 - 只能表明其中一個(gè)已執(zhí)行結(jié)束。

如果其中一個(gè)任務(wù)執(zhí)行結(jié)束(或者拋了一個(gè)異常),其他 Callable 將被取消。

以下是示例代碼:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 1";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 2";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 3";}
});
String result = executorService.invokeAny(callables);
System.out.println("result = " + result);
executorService.shutdown()

上述代碼將會(huì)打印出給定 Callable 集合中的一個(gè)的執(zhí)行結(jié)果

invokeAll()

invokeAll() 方法將調(diào)用你在集合中傳給 ExecutorService 的所有 Callable 對(duì)象。invokeAll() 返回一系列的 Future 對(duì)象,通過它們你可以獲取每個(gè) Callable 的執(zhí)行結(jié)果。

記住,一個(gè)任務(wù)可能會(huì)由于一個(gè)異常而結(jié)束,因此它可能沒有 “成功”。無(wú)法通過一個(gè) Future 對(duì)象來告知我們是兩種結(jié)束中的哪一種。

以下是一個(gè)代碼示例:

ExecutorService executorService = Executors.newSingleThreadExecutor();
Set<Callable<String>> callables = new HashSet<Callable<String>>();
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 1";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 2";}
});
callables.add(new Callable<String>() {public String call() throws Exception {return "Task 3";}
});
List<Future<String>> futures = executorService.invokeAll(callables);
for(Future<String> future : futures){System.out.println("future.get = " + future.get());
}
executorService.shutdown();

ExecutorService關(guān)閉

使用完 ExecutorService 之后你應(yīng)該將其關(guān)閉,以使其中的線程不再運(yùn)行。比如,如果你的應(yīng)用是通過一個(gè) main() 方法啟動(dòng)的,之后 main 方法退出了你的應(yīng)用,如果你的應(yīng)用有一個(gè)活動(dòng)的 ExexutorService 它將還會(huì)保持運(yùn)行。ExecutorService 里的活動(dòng)線程阻止了 JVM 的關(guān)閉。

要終止 ExecutorService 里的線程你需要調(diào)用 ExecutorService 的 shutdown() 方法。

ExecutorService 并不會(huì)立即關(guān)閉,但它將不再接受新的任務(wù),而且一旦所有線程都完成了當(dāng)前任務(wù)的時(shí)候,ExecutorService 將會(huì)關(guān)閉。在 shutdown() 被調(diào)用之前所有提交給ExecutorService 的任務(wù)都被執(zhí)行。

如果你想要立即關(guān)閉 ExecutorService,你可以調(diào)用 shutdownNow() 方法。這樣會(huì)立即嘗試停止所有執(zhí)行中的任務(wù),并忽略掉那些已提交但尚未開始處理的任務(wù)。無(wú)法擔(dān)保執(zhí)行任務(wù)的正確執(zhí)行??赡芩鼈儽煌V沽?#xff0c;也可能已經(jīng)執(zhí)行結(jié)束。

最后感謝每一個(gè)認(rèn)真閱讀我文章的人,禮尚往來總是要有的,雖然不是什么很值錢的東西,如果你用得到的話可以直接拿走:

這些資料,對(duì)于【軟件測(cè)試】的朋友來說應(yīng)該是最全面最完整的備戰(zhàn)倉(cāng)庫(kù),這個(gè)倉(cāng)庫(kù)也陪伴上萬(wàn)個(gè)測(cè)試工程師們走過最艱難的路程,希望也能幫助到你!?

http://m.aloenet.com.cn/news/34620.html

相關(guān)文章:

  • 企業(yè)網(wǎng)盤怎么下載文件seo是什么服
  • 網(wǎng)站設(shè)計(jì) 重慶seoul是啥意思
  • 嵐山網(wǎng)站建設(shè)報(bào)價(jià)老鐵外鏈
  • 微網(wǎng)站建設(shè)使用程序西安關(guān)鍵詞排名首頁(yè)
  • 門戶網(wǎng)站概念網(wǎng)絡(luò)營(yíng)銷推廣服務(wù)
  • 怎樣做類似淘寶網(wǎng)的網(wǎng)站汕頭網(wǎng)站優(yōu)化
  • 用html編寫淘寶網(wǎng)站怎么做seo友情鏈接
  • 漢子由來 外國(guó)人做的網(wǎng)站網(wǎng)站建設(shè)公司服務(wù)
  • 南和網(wǎng)站建設(shè)公司網(wǎng)絡(luò)推廣費(fèi)用計(jì)入什么科目
  • 程序開源網(wǎng)站關(guān)鍵詞列表
  • 新手學(xué)易語(yǔ)言多久可以做網(wǎng)站中國(guó)優(yōu)秀網(wǎng)頁(yè)設(shè)計(jì)案例
  • 本地旅游網(wǎng)站模版網(wǎng)絡(luò)營(yíng)銷網(wǎng)站推廣方法
  • 做公司網(wǎng)站多少錢站長(zhǎng)工具在線查詢
  • 網(wǎng)站背景色最新天氣預(yù)報(bào)最新消息
  • 如何做網(wǎng)站刷題西安網(wǎng)站建設(shè)
  • 做企業(yè)網(wǎng)站的架構(gòu)圖廣州王牌seo
  • 公司做網(wǎng)站流程關(guān)鍵詞挖掘工具愛網(wǎng)
  • 菲律賓有做網(wǎng)站的嗎seo優(yōu)化是做什么的
  • 安卓手機(jī) 做網(wǎng)站湘潭seo優(yōu)化
  • 有哪些做留學(xué)資訊的網(wǎng)站搜全網(wǎng)的瀏覽器
  • 豬八戒做網(wǎng)站怎么樣打開百度一下的網(wǎng)址
  • 服務(wù)器安全設(shè)置河南網(wǎng)站seo費(fèi)用
  • 網(wǎng)站域名不合法新聞最新消息
  • 建設(shè)單位企業(yè)鎖登陸網(wǎng)站seo沈陽(yáng)
  • 做中英文游戲門戶網(wǎng)站關(guān)鍵詞怎么弄百度一下的網(wǎng)址
  • 500人在線網(wǎng)站建設(shè)配置國(guó)家市場(chǎng)監(jiān)管總局官網(wǎng)
  • 武漢武昌做網(wǎng)站推廣百度推廣需要什么條件
  • 長(zhǎng)沙做網(wǎng)站好的公司有哪些跨境電商平臺(tái)哪個(gè)最好最可靠
  • 做第三方的qq互聯(lián)接口時(shí)_回調(diào)到自己的網(wǎng)站時(shí)要延時(shí)很久是什么原因品牌推廣平臺(tái)
  • 網(wǎng)站域名301是什么意思什么是長(zhǎng)尾關(guān)鍵詞舉例