文章目錄

其實、原本沒打算要繼range再接下去寫一篇的~
可是,總覺得上一篇有一點點不完整耶~ 依我貓毛的個性來說。所以、來補一下好了。

這篇應該會探討一下、ㄜ~ 我基於野生動物的直覺上的不知道正不正確的效能分析~(汗|||) 就算個小紀錄好了唄~(攤手)

是的、基於現在的電腦配備越來越好、功能希望越快推出越好、東西寫完後就丟在一邊再也不想理他,遇到新需求…好吧~那
砍掉重寫比較快…。在這類的狀況和習慣下,大家漸漸的遺忘在不久前(?),前輩們為了在有限的環境下,也許為了一個
register、為了快1ms,計較再計較的心情。

很幸運的,在唸書時期,因為修了一些課,還真的讓我體會到什摸叫做『計較再計較』…。因此、養成了我不自覺得在
coding的過程中,會很自然的『計較再計較』。

好~回憶完、馬上進入正題,這次是要來探討下列$\eqref{eq:fn1}$ 和 $\eqref{eq:fn2}$ 在性能還有狀況下的微妙差異:

$$
\begin{equation}
\text{Let}~x\in\mathbb{R},
n1 \le x \wedge x \le n2
\label{eq:fn1}
\end{equation}
$$

$$
\begin{equation}
\text{Let}~x\in\mathbb{R},
\ (x - n1) \times (x - n2) \le 0
\label{eq:fn2}
\end{equation}
$$

首先、我們先來看…在程式中、他們大概會是怎樣運作的 (我想、大概是這樣啦~ XDD|||)

  • 先來看$\eqref{eq:fn1}$

    1. 先計算 $n1 \le x$,條件成立進入 2.,不成立、依狀況做 jump。
    2. 計算 $x \le n2$,條件成立進入 3.,不成立、依狀況做 jump。
    3. 將1. 和 2. 的結果做… logic運算,依結果做jump。
  • 接下來是$\eqref{eq:fn2}$

    1. 計算 $x - n1$
    2. 計算 $x - n2$
    3. 計算 1. X 2.
    4. 判斷結果、依狀況做 jump。

看起來、其實差不多對吧~搞不好有人會認為~$\eqref{eq:fn2}$還比較麻煩咧~ 其實…如果、有寫過assembly也許會比較
有fu。(←可以更好的挑出我哪邊有問題~ XDD|||)

  • 其實在做$\le$ 和 $\ge$判斷上、底層的實做依然是使用$-$、也就是說在$\eqref{eq:fn1}\$中的step1和step2,他們必
    須經過減法的計算再經過判斷,才能決定要不要繼續往下做,並且…還需要各增加一個label做jump。照上述、我們大概
    可以粗略的幫$\eqref{eq:fn1}$下個結論:

    • 最多~會需要做… 3次op、3次jump。
    • 最少~會需要…1次op、1次jump。
  • 反觀、在$\eqref{eq:fn2}$中,底層的實做其實是一連串的數字運算、然後在最後才需要做jump,也就是說…在
    $\eqref{eq:fn2}$中,其實需要做jump的機會是比較少的。這個、我們也可以替$\eqref{eq:fn2}$下個結論:

    • 最多~會需要做…3次op、1次jump。
    • 最少咧~還是需要做3次op、1次jump。

也許、大家看過後,還是不會有感覺啦~、搞不好還會覺得、$\eqref{eq:fn2}$還比較糟,人家$\eqref{eq:fn1}$的 best
case 只要、刷刷2次運算就可以跳到要執行的地方了咧~!! 是的、這也就是為啥、其實我在上次的文章中,並沒有說過
我再也不用$\eqref{eq:fn1}$的方式,它的確還是有它的優勢存在。

而、為什摸在大部分的情況下,我仍然會推薦使用$\eqref{eq:fn2}$咧~。 我們知道、在c/c++這類需要compiler後、產生
obj然後還需要link的語言來說、那些東西其實都會經過一些優化和修飾。然而、在script的語言中、基本上啦~它很難做到
非常好的優化,雖然、並不能說沒有(像v8很像就對new object 這類的有優化)。可是、如果可以盡可能的減少jump、那~
還是可以少很多工耶~也許大家不太有感覺。不過、身為常常在大資料下、又沒有太多資源可以使用的情況下。我覺得差
很多。

而且、Q 口Q 大家知道、計算jump 的位置有多麻煩嗎~ 真的、真的、真的灰~~常麻煩 不騙你們…。你以為、只要建
一下label就好了嗎~ Q 口Q 那個、是人類眼睛看到的、實際上,它定址的方式有很多種咧~根據實做的方式、有非常多的
差異 (好吧~ 其實我並沒有很認真的猜測過script語言怎摸處理jump這類的) 我打從心裡的認為、大家的jump的方式應該
是大同小異啦~所以、想要jump、至少還需要做1次的fetch、1次的load、然後算出pc、把data push到stack再jump過去、
jump過去後再把data給pop出來… balabala ($\leftarrow$應該有遺漏掉一些正確的步驟)。也就是說…在
$\eqref{eq:fn1}$的情況、除非~大部分都是 best case、要不~很難好好的估計它的時間…。所以、我認為在平均上,
如果可以讓best case和worst case的運算時間比較一致、也是不錯的吧~ 沒有人能確定自己會不會那摸…

嗯、也就是說,我喜歡best case 和 worst case的差異不會很大,即使在best case下、比直覺式寫法還要來的慢一些些,
我是可以接受的啦~ 不過、這也還蠻看情況的,就像 10 筆資料的搜尋、你會使用超好寫的sequence 搜尋、還是先sort 再
做 binary; 10,000 筆資料、你還會繼續使用超好寫的sequence、還是使用heap。雖然並沒有堅持哪種寫法好,兩種我也
都會使用啦~不過、我確定的是、在做重構的時候,我自己會有60%~70%的比例、會改寫成第二種寫法,和其他寫法做搭配。

真的、script語言寫起來、理論上寫起來的彈性貌似很大…。根據我少少的寫js和lisp的經驗來說,也真的很大啦~。
它們可以做到很多別人不好做到的事情。但是、一寫不好,我的天~那個效能也是會有令人想像不到的…唔…成長。在
這方面、我始終認為、拋去它的一些特性,這是它頗有難度的地方。

當然、如何在容易看得懂程式、以及希望可以兼具效能和彈性上…balabala等眾多貪心的需求上達到一個平衡,真的是個很
困難的課題,希望…我可以再更進一步的窺見其中的奧秘。(由衷的希望用腦波coding的工具可以趕快被生出來~ XDD)

文章目錄