天天看點

RxJava 中的多線程RxJava 中的多線程

<b>本文講的是RxJava 中的多線程,</b>

大多數情況下,我寫的 Android 代碼都是可以流暢運作的。直到上幾周編寫一個需要讀取和分析大型檔案的 app 之前,我從未關心過 app 運作速度的問題。

盡管我期望使用者明白檔案越大,耗時越長的道理,有時候他們仍會放棄我的應用。他們可能認為應用卡住了,也可能是因為他們就不想等那麼久。是以如果我能把時間縮短至少一半的話,一定會大有裨益的。

因為我所有背景任務都用 RxJava 重寫了,是以繼續用 RxJava 來解決這個問題也是自然而然的。尤其是我還有一些如下所示的代碼:

是以我隻是想把循環的每個操作放到一個背景線程中。如下所示:

的确起作用了,時間減少了近一半。但也導緻大量垃圾回收(GC),這使得加載時的 UI 又卡又慢。為了搞清楚問題的原因,我加了一句 log 列印如下資訊<code>Thread.currentThread().getName()</code>。 這樣我就搞清楚了,我在處理每一段資料時都建立了線程。正如結果所示,建立上千個線程并不是什麼好主意。

我已經完成了加速資料處理的目标,但運作起來并不那麼流暢。我想知道如果不觸發這麼多 GC 的話還能不能跑得再快點。是以我自己寫了一個線程池并指定了最大線程數來供 RxJava 調用,省的每次處理資料都要建立新線程:

對于單個資料都很大的資料集來說,這樣減少了約 10% 的資料處理時間。然而,對于單個資料都很小的資料集就減少了約 30% 的時間。同時也減少了 GC 的調用次數,但 GC 還是太頻繁。

上文中我提到用兩類資料集進行測試,一類的資料本身是大檔案,但是資料集裡包含的資料個數很少;另一類資料集裡的每一個資料并不是很大,但是包含資料的總量很多。當我再次測試時,第一組資料幾乎沒差别,而第二組改變相當大。之前幾乎要 20秒,現在隻需 5秒。

第二類資料集運作時間改進了如此大的原因,是因為每個線程不再處理一個資料(而是處理一個從總體資料集裡拆分下來的小資料集)。之前每一個資料,都需要調用一個線程來處理。現在我減少了調用線程的次數,進而提升了性能。

上面的代碼要執行并發還有一些地方需要修改,是以我整理了代碼并放到工具類中,使其更具有通用性。

這裡 <code>T</code> 是被處理的資料類型,樣例中是<code>DataModel</code>。傳入待處理的 <code>List&lt;T&gt;</code> 并期望結果是<code>U</code>。在我的樣例中 <code>U</code> 是 <code>List&lt;DataModel&gt;</code>,但它可以是任何東西,并不一定是一個 list。傳入的回調函數負責資料子清單具體的業務處理并傳回結果。

事實上影響運作速度的因素有許多。比如線程管理方式,線程數,裝置等。大多數因素我無法控制,但總有一些是我沒有考慮到的。

如果每個資料大小不相等會怎麼樣?舉個例子,如果有 4 個線程,每個被指派給第 4 線程的資料大小是被指派給其他線程的十倍會怎麼樣?這時第四個線程的耗時就是其他線程的大約 10 倍。這種情況下使用多線程就不會減少多少時間。我的第二次嘗試基本解決了這個問題,因為線程隻在需要時才初始化。但這個方法太慢了。

我也試過改變資料分組方式。作為随意配置設定的取代,我可以跟蹤每一組資料的總量,然後将資料配置設定給最少的那組。這樣每個線程的工作量就接近平均了。倒黴的是,測試之後發現這樣做增加的時間遠大于它節省的時間。

資料被配置設定的大小越平均,處理速度就越快。但大多數情況下,随機配置設定看起來更快些。理想情況下是每個線程一有空就配置設定任務,同時執行配置設定所消耗的資源也少,這是最高效的。但我找不到一個足夠高效的可以減少配置設定瓶頸的方法。

是以如果你想用多線程,這是我的建議。如果你有什麼好想法,請務必告訴我。得到一個最優解(如果有的話)總是很難的。以及,能用多線程并不意味着必須用多線程。。

<b></b>

<b>原文釋出時間為:2017年4月25日</b>

<b>本文來自雲栖社群合作夥伴掘金,了解相關資訊可以關注掘金網站。</b>