程序|只要使用這個功能,程序運行速度瞬間提升,高到離譜!

2020-12-23 mySoulCode

hello !我是小小,今天是本周的第二篇,本篇將會著重的講解關於Java並行流的知識

前言

在之前如果需要處理集合需要先手動分成幾部分,然後為每部分創建線程,最後在合適的時候合併,這是手動處理並行集合的方法,在java8中,有了新功能,可以一下開啟並行模式。

並行流

認識開啟並行流

並行流是什麼?是把一個流內容分成多個數據塊,並用不同線程分別處理每個不同數據塊的流。例如,有下面一個例子,在List中,需要對List數據進行分別計算,其代碼如下所示:

List<Apple> appleList = new ArrayList<>(); // 假裝數據是從庫裡查出來的for (Apple apple : appleList) { apple.setPrice(5.0 * apple.getWeight() / 1000);}在這裡,時間複雜度為O(list.size),隨著list的增加,耗時也在增加。並行流可以解決這個問題,代碼如下所示:

appleList.parallelStream().forEach(apple -> apple.setPrice(5.0 * apple.getWeight() / 1000));這裡通過調parallelStream()說明當前流為並行流,然後進行並行執行。並行流內部使用了默認的ForkJoinPool線程池,默認線程數為處理器的核心數。

測試並行流

普通代碼如下所示:

public static void main(String[] args) throws InterruptedException { List<Apple> appleList = initAppleList(); Date begin = new Date(); for (Apple apple : appleList) { apple.setPrice(5.0 * apple.getWeight() / 1000); Thread.sleep(1000); } Date end = new Date(); log.info("蘋果數量:{}個, 耗時:{}s", appleList.size(), (end.getTime() - begin.getTime()) /1000);}輸出的內容為耗時4s。

並行代碼如下所示:

List<Apple> appleList = initAppleList();Date begin = new Date();appleList.parallelStream().forEach(apple -> { apple.setPrice(5.0 * apple.getWeight() / 1000); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } );Date end = new Date();log.info("蘋果數量:{}個, 耗時:{}s", appleList.size(), (end.getTime() - begin.getTime()) /1000);輸出結果為耗時1s。可以看到耗時大大提升了3s。

並行流拆分會影響流的速度

對於並行流來說需要注意以下幾點:

對於 iterate 方法來處理的前 n 個數字來說,不管並行與否,它總是慢於循環的,而對於 LongStream.rangeClosed() 方法來說,就不存在 iterate 的第兩個痛點了。它生成的是基本類型的值,不用拆裝箱操作,另外它可以直接將要生成的數字 1 - n 拆分成 1 - n/4, 1n/4 - 2n/4, ... 3n/4 - n 這樣四部分。因此並行狀態下的 rangeClosed() 是快於 for 循環外部迭代的代碼如下所示:

package lambdasinaction.chap7;import java.util.stream.*;public class ParallelStreams { public static long iterativeSum(long n) { long result = 0; for (long i = 0; i <= n; i++) { result += i; } return result; } public static long sequentialSum(long n) { return Stream.iterate(1L, i -> i + 1).limit(n).reduce(Long::sum).get(); } public static long parallelSum(long n) { return Stream.iterate(1L, i -> i + 1).limit(n).parallel().reduce(Long::sum).get(); } public static long rangedSum(long n) { return LongStream.rangeClosed(1, n).reduce(Long::sum).getAsLong(); } public static long parallelRangedSum(long n) { return LongStream.rangeClosed(1, n).parallel().reduce(Long::sum).getAsLong(); }}package lambdasinaction.chap7;import java.util.concurrent.*;import java.util.function.*;public class ParallelStreamsHarness { public static final ForkJoinPool FORK_JOIN_POOL = new ForkJoinPool(); public static void main(String[] args) { System.out.println("Iterative Sum done in: " + measurePerf(ParallelStreams::iterativeSum, 10_000_000L) + " msecs"); System.out.println("Sequential Sum done in: " + measurePerf(ParallelStreams::sequentialSum, 10_000_000L) + " msecs"); System.out.println("Parallel forkJoinSum done in: " + measurePerf(ParallelStreams::parallelSum, 10_000_000L) + " msecs" ); System.out.println("Range forkJoinSum done in: " + measurePerf(ParallelStreams::rangedSum, 10_000_000L) + " msecs"); System.out.println("Parallel range forkJoinSum done in: " + measurePerf(ParallelStreams::parallelRangedSum, 10_000_000L) + " msecs" ); } public static <T, R> long measurePerf(Function<T, R> f, T input) { long fastest = Long.MAX_VALUE; for (int i = 0; i < 10; i++) { long start = System.nanoTime(); R result = f.apply(input); long duration = (System.nanoTime() - start) / 1_000_000; System.out.println("Result: " + result); if (duration < fastest) fastest = duration; } return fastest; }}共享變量會造成數據出現問題

public static long sideEffectSum(long n) { Accumulator accumulator = new Accumulator(); LongStream.rangeClosed(1, n).forEach(accumulator::add); return accumulator.total;}public static long sideEffectParallelSum(long n) { Accumulator accumulator = new Accumulator(); LongStream.rangeClosed(1, n).parallel().forEach(accumulator::add); return accumulator.total;}public static class Accumulator { private long total = 0; public void add(long value) { total += value; }}並行流的注意

儘量使用 LongStream / IntStream / DoubleStream 等原始數據流代替 Stream 來處理數字,以避免頻繁拆裝箱帶來的額外開銷要考慮流的操作流水線的總計算成本,假設 N 是要操作的任務總數,Q 是每次操作的時間。N * Q 就是操作的總時間,Q 值越大就意味著使用並行流帶來收益的可能性越大對於較少的數據量,不建議使用並行流容易拆分成塊的流數據,建議使用並行流關於作者

我是小小,一枚一線程序猿,我們下期再見~bye

END

相關焦點

  • 谷歌免費視頻聊天應用程式Meet的功能以及如何使用
    谷歌最近加入了這些公司,向所有人提供獨特的谷歌 Meet服務,只要擁有谷歌帳號即可使用。什麼是谷歌 Meet?此前,Meet是G Suite軟體包的一部分,是谷歌為公司、組織和學校提供的可作為共享和生產應用程式的一種商業解決方案,但在谷歌發布新聲明後,任何人都可以在網上免費獲得Meet應用。谷歌說:「從5月初開始,任何擁有電子郵箱的人都可以加入Meet應用程式,享受許多商業和教育用戶使用的相同功能。」
  • 蘋果12怎麼關閉運行程序 iPhone12怎麼關閉後臺程序
    蘋果12怎麼關閉運行程序 iPhone12怎麼關閉後臺程序 蘋果iPhone12手機已經發售上市,已有很多用戶開始使用
  • 微信小程序運行內存不足怎麼解決?微信小程序運行內存不足的解決...
    相信很多朋友都有在使用手機微信,那麼大家在使用手機微信小程序的時候,是否有過提示內存不足,無法使用小程序的情況呢?關於這個問題,接下來小編就和大家分享一下我的解決方法,希望能夠幫助到大家。在打開微信小程序或小遊戲的時候,有時會出現「運行內存不足」類似的提示,導致無法正常打開使用。那麼用戶要如何解決這個問題呢?
  • 如何讓微信小程序快速接入七牛雲
    從小程序的熱門應用場景來看,大概可以分為兩大類,一類是低使用頻率的 App,如金融類的銀行或保險公司 App,O2O 類的上門做飯、家政 App;另一類是雖然使用頻率高但是功能簡單的 App,如工具類的天氣、快遞查詢,富媒體類的資訊 App 等。那麼,誰將成為小程序的大贏家?
  • 看過來 提升Win10運行速度基本優化設置方案放送
    【PConline資訊】升級Win10系統使用一段時間後,很多用戶遇到了運行速度變慢的問題,其實這需要進行一些Win10系統的基本優化設置,下面小編給大家分享有效提升Win10運行速度的基本優化設置方案。
  • 小程序插入直播功能代碼
    小程序插入直播功能我們的商城小程序被邀請開通了直播功能。直播功能還是很有吸引力的,可以在小程序內流暢完成購買交易閉環,提升轉化率;所以開發工作立馬安排上了。小程序直播組件包括觀眾端、主播端及後臺管理端,其中觀眾端提供拉流、實時互動、訂閱提醒、商品購買等能力,主播端提供開播、推流、音視頻效果優化等能力,後臺管理端則負責直播房間、商品貨架以及營銷活動配置等。所以,大部分的工作其實是管理和運營來做,小程序上只要做好直播入口的跳轉進入。直播功能的接入,微信這次做得不錯。接入的開發工作按照文檔很容易就完成了。
  • FANUC機器人:奇異點迴避功能介紹與使用方法
    機器人在通過這些腕部奇異點或者其附近時,機器人腕部軸中的J4軸與J6軸,將在短時間內進行迴轉量大的運動,使機器人產生極度怪異的運動姿態;若是此時限制腕部軸的運行速度,則會導致工具中心點(TCP)的速度變慢,同時機器人也將與所示教的運行軌跡產生偏離。
  • 可直接運行 EXE 程序
    這位巴西網友可能比較喜歡 Windows 10 的界面風格吧,所以就基於 Ubuntu 與 Cinnamon 桌面然後發行了這款「Linuxfx」系統,雖然是 Linux 的核心,但界面都模仿了 Windows 10,最騷的是還可以直接運行 EXE 程序。
  • 單片機控制程序加密方法與程序安全
    大家都知道,單片機應用系統由硬體電路與控制程序兩部分組成,儘管硬體電路部分同樣凝聚了設計者的心血,也體現了設計者創造性勞動成果,但卻無密可守,惟一有保密可能的就是控制程序部分。確定頻率誤差範圍的原則是同一晶片保證每次上電復位後測到的數據均在誤差允許範圍內,因此允許誤差不宜太小;另一方面,不同晶片頻率相同的可能性又要儘可能小,因此頻率誤差允許範圍也不能太大)。因此,只要上電後測到的RC振蕩器頻率與ID號相比,誤差在1%以內即認為合法,反之視為非法。該加密方式流程大致如圖2所示。
  • 使用支持谷歌Translate應用程式離線翻譯的相同模型
    本機應用程式開發人員可以將Performance Monitoring SDK集成到他們的應用程式中,以收集性能數據,然後可以在Firebase Performance Monitoring中對其進行分析;很快,Web開發人員也將能夠在Firebase中跟蹤其Web應用程式的性能。我與Firebase產品負責人Francis Ma進行了交談,以了解有關這些更改的更多信息。
  • ...寫出什麼樣的程序才算是好的程序?一千個讀者就有一千個哈姆雷特
    有的人認為,我寫程序很厲害,同樣的功能使用的變量更少。 這確實在一定程度上說明你可能有些厲害,但多數情況下算不上好程序。 還有的人認為,程序行數少。 曾經看到一個同學使用遞歸函數實現字符串的逆序處理,非常簡短的代碼。不能說程序寫得不好,但遞歸深度太大消耗內存很嚴重。一般也不太容易想到。 還有的說,我的程序運行得快了一些。 程序效率高運行快,固然也是好的。
  • 在MAC上同時運行蘋果和Windows的程序
    一個根本的原因,是使用習慣。另一個原因,是應用軟體 習慣就沒有什麼可說了,因人而異。 軟體則是一個硬傷。有多硬?套用一句蘋果的廣告語「如果你沒有XX,就沒有XX」。試想,如果你工作上有一個業務程序只能在Windows上跑,那你們公司就得乖乖的配一臺PC給你。
  • 一款功能豐富的Perl後門程序分析
    功能包括:DDoS(udpflood、tcpflood、httpflood、sqlflood)、hacking(埠掃描、信息收集、本地root、日誌清理等)情報信息搜集(packetstorm、milw0rm)等一、樣本信息:蜜罐日誌顯示黑客使用密碼猜解成功登陸SSH後用wget命令下載了程序:文件信息:
  • 都有哪些微信小程序?最新微信小程序推薦!
    都有哪些微信小程序?最新微信小程序推薦!備受關注的微信小程序在今天正式上線了,所有功能都是圍繞「觸手可及,用完即走」這一理念設計。從視頻體驗來看,得益於Android由於系統的開放,我們可以將小程序放到桌面上,點開即可跳轉到小程序頁面,當微信在後臺運行時,基本秒開,啟動速度比APP還快!無奈目前微信中沒有給小程序預留入口,想要進入小程序目前有三個方法:掃描二維碼;別人分享;搜索。
  • Titan系列控臺V11版本開機自動運行程序的設置方法!
    在Titan系列V11版本上更新了一個開機自動運行程序的功能,包括運行Cue、Chase、Cue List。適合在一些文旅項目,或者固定演出場所中使用,下面就來看怎麼設置!1、點擊回放選項,再點擊程序的藍色按鈕。
  • 如何在 Ubuntu 16.10 的 Unity 8 上運行老式 Xorg 程序
    這項技術已經在 Ubuntu phone 和平板上大量使用,但是這次新版是我們在桌面環境上第一次見到 Mir 。這項技術相當新穎,結果是沒多少 Linux 程序能運行在它之上。不是所有,那也是大部分的程序設計在 Xorg 和 X11 之上運行。如果你想要試試在 Unity 8 上運行這些程序,你肯定會為在 Unity 8上確實能夠運行之前的 Xorg 程序而高興。接下來是如何做!
  • iOS 14或將推出系統級「小程序」功能:無需下載APP即可使用
    iOS 14或將推出系統級「小程序」功能:無需下載APP即可使用 2020-04-10 18:31 來源:澎湃新聞·澎湃號·湃客
  • 擁抱ARM,Windows10發布新補丁,可運行64位程序
    近日,微軟在開發者中心正式推出可以在 ARM 架構電腦上模擬 64 位 x86 程序的新版 Windows 10。使用搭載ARM架構處理器的Windows 10用戶安裝該補丁之後,可以直接在電腦運行絕大多數Windows exe應用程式,不會因為兼容性問題而無法運行。
  • AutoVoiceChrome擴展程序具有始終收聽功能
    目前處於開發人員預覽階段,因此它目前尚不具備他們計劃的所有功能。我們將不得不等待,看看是否有更多的第三方公司開始在其產品中使用該平臺,但是一位受歡迎的Android開發人員最近修改了示例代碼,並將其注入了他們的Google Chrome擴展程序中。我們已經多次討論過Joao Dias的應用程式,因為他們的Tasker插件允許我們的設備提供更多自定義選項。
  • 如何在 Ubuntu/Debian Linux 上編寫、編譯和運行一個 C 程序
    在基於 Debian 和 Ubuntu 的 Linux 發行版中,使用 apt 命令:sudo apt install gcc切換到保存你的 C 程序的目錄(或者提供路徑),然後通過編譯程序生成對象文件