天天看點

延遲求值-如何讓Lo-Dash再提速x100?延遲求值流水線延遲執行後記

「注釋」作者在本文裡沒有說明這麼一個事實: 目前的版本<code>Lo-Dash v2.4.1</code>并沒有引入延遲求值的特性,<code>Lo-Dash 3.0.0-pre</code>中部分方法進行了引入,比如<code>filter()</code>,<code>map()</code>,<code>reverse()</code>。 原文
延遲求值-如何讓Lo-Dash再提速x100?延遲求值流水線延遲執行後記

但似乎我錯了-還可以讓<code>Lo-Dash</code>有明顯的提升。隻需将關注點從細微的優化轉移到算法上來。譬如,在一次循環中我們往往會去優化循環體:

但針對循環體的優化往往很難,很多時候已經到極限了。相反,優化<code>getLength()</code> 函數盡量減少循環次數變得更有意義了。你想啊,這個數值越小,需要循環的<code>10ms</code>就越少。

這便是<code>Lo-Dash</code>實作延遲求值的大緻思路。重要的是減少循環次數,而不是每次循環的時間。讓我們考察下面的例子:

我們隻想取出3個價格低于10元的小球。通常情況下我們先過濾整個資料源,最後從所有小于10的元素裡傳回前面三個即可。

延遲求值-如何讓Lo-Dash再提速x100?延遲求值流水線延遲執行後記

但這種做法并不優雅。它處理了全部8個資料,但其實隻需要處理前面5個我們就能拿到結果了。同樣為了得到正确的結果,延遲求值則隻處理最少的元素。優化後如下圖所示:

延遲求值-如何讓Lo-Dash再提速x100?延遲求值流水線延遲執行後記

一下子就獲得了37.5%的性能提升。很容易找出提升X1000+的例子。比如:

延遲求值-如何讓Lo-Dash再提速x100?延遲求值流水線延遲執行後記

延遲求值同時帶來了另一個好處,我稱之為“流水線”。要旨就是避免産生中間數組,而是對一個元素一次性進行完所有操作。下面用代碼說話:

上面看似優雅的寫法在原始的<code>Lo-Dash</code>裡會轉換成下面的樣子(直接求值):

當引入了延遲求值後,代碼大緻就成這樣的了:

減少不必要的中間變量多少會帶來性能上的提升,特别是在資料源特别巨大,記憶體又吃緊的情況下。

延遲求值帶來的另一個好處是延遲執行。無論何時你寫了段鍊式代碼,隻有在顯式地調用了<code>.value()</code>後才會真正執行。這樣一來,在資料源需要異步去拉取的情況下,可以保證我們處理的是最新的資料。

而且這種機制在某些情況下也會提高執行效果。我們可以老早發送一個請求擷取資料,然後指定一個精确的時間來執行。

繼續閱讀