--- title: 淺談指令效能分析 tags: math, started --- # 淺談指令效能分析 指令效能分析是指令設計中非常重要的一環,指令設計方式差者可以嚴重影響到地圖的順暢度, 故我們之後會特別將其額外分離成一個研究主題, 其中將低效能(低順暢度)轉換成高效能(高順暢度)的步驟又稱之為 <font color=blue>優化(Optimize)</font>, 而在此篇中我們只會淺談與淺度分析一些常見的優化指令技巧 > 詳細的分析可以查看我們的另一個文章分類:[Minecraft 指令效能分析](https://hackmd.io/@mccmd-analyzed/By-kvNtUO) --- # 一、時間複雜度(Time Complexity) ### 一般的表示法(T) 其記錄數值的方式,便是用一個字母「T」的函式形式做表達,代表一個時間(Time)消耗的概念 * 執行 $n$ 次 <font color=red>$⇒ T(n)$ </font> ### Big-O表示法(O) 其記錄數值的方式,便是用一個字母「O」的函式形式做表達, 其表示法常會省略掉 <font color=blue>係數、常數項、低次項</font> 的部分,以下舉例: `ex.` $T(50n)$ <font color=red>$⇒ O(n)$ </font> `ex.` $T(7n^2+3n+1)$ <font color=red>$⇒ O(n^2)$ </font> `ex.` $T(10⋅(\log_2n)^3 + 1000⋅\log_2n)$ <font color=red>$⇒ O(\log^3n)$ </font> `ex.` $T(\sqrt{n}+(\log_2n)^3+\log_2n)$ <font color=red>$⇒ O(\sqrt n)$ </font> 假設目標是生成n隻殭屍,那麼其「生成殭屍所消耗的時間」會被計為 $O(n)$ > 對數(Logarithm) : $a^y=x \Rightarrow \log_a x=y$ > > 以下的 $\log N$ 皆為 $\log_2N$ 的簡寫,而不是 $\log_{10}N$ > 請注意,log函式的省略底數格式,在電腦時間分析相關部分,其底數通常為2 其順序比較是這樣排序的: $O(1) < O(\log n) < O(\sqrt n) < O(n) < O(n\log n) < O(n^2) < O(a^n) < O(n!)$ ![](https://i.imgur.com/O58Qvwo.png =65%x) 在此篇分析大部分「指令執行時間」上,我們會使用此兩種方式來表示, 在大多情況我們會更傾向使用Big-O表示法 (因為T的係數項大多情況是無法得知的) --- # 二、集合(Set) 在分析上,我們可以利用數學中的集合來將目標實體用符號表示的方式分群, 這也是我們本篇會常出現的方式, 範例為假設有一集合 $S = \{1,2,3\}$ | 符號表示法 | | 範例 | | | ---------- | ------------ | -- | -- | | $E\in S$ | $E$ 屬於 $S$ | $1\in S$ | $1$ 屬於 $S$ | | $\|S\|$ | $S$ 的元素個數 | $\|S\|=3$ | $S$ 有三個元素 | | $A\subset S$ | $A$ 包含於 $S$ // $A$ 被 $S$ 包含 | $\{1,2\}\subset S$ | $\{1,2\}$ 包含於 $S$ | > 小小的英文科普 > 屬於:A belongs to B > 包含於:A is a subset of B --- # 三、實體選擇器(selector)的運作方式 首先要特別留意的一點,selector除了`@s`之外,皆會搜索全部的實體或玩家, 假設玩家(Players)的集合為 $P$、實體(Entities)的集合為 $E$,且 $P\subset E$ (實體中含有玩家), 以下我們會區分幾種複雜度的變數分別為: | 選擇器 | 掃描目標的範圍,以及其時間複雜度的分析 | | -------- | -------- | | `@a` | 複雜度至少為 $O(\|P\|)$,代表掃描全部共 $\|P\|$ 個玩家 | | `@e, @p` | 複雜度至少為 $O(\|E\|)$,代表掃描全部共 $\|E\|$ 個實體 | | `@s` | 複雜度為 $O(1)$,僅掃描自己本身 <font color=red>(最優的選擇器)</font> | --- # 四、Minecraft 背景演算法與資料結構 * 儲存實體:**Array List** * 選擇實體時亦會創建並傳遞一個實體List * 實體排序:**Merge Sort** * 排序的時間為:$O(n \log n)$,$n$ 為實體或目標數量,會生成一個新的Array List * 數量指定(`limit`):整個都排序完後才會抓數量,<font color=red>會消耗額外時間</font> * 預處理: * 當List中的實體只剩下一個時,不會執行排序的動作 * 當List中只有玩家的時候,會只跑「玩家的排序算法」 * 實體儲存Tags:**Hash Set<String>** * 查詢、插入與移除的時間皆為:$O(1)$ * 呼叫Function : **Immutable HashMap** * 查詢、插入與移除的時間皆為:$O(1)$ --- # 五、一些實體選擇器的時間分析範例 以下簡寫 $|E|$ 為$E$、$|P|$ 為$P$,以避免太過眼花撩亂 | 指令 | 時間複雜度 | | --------------------- | ---------- | | `execute as @e as @e` | $O(E^2)$ | | `execute as @a as @e` | $O(P\cdot E)$ | | `execute as @e as @a` | $O(E\cdot P)$ | | `execute as @e[tag=target_tag]` | $O(E)$ | | `execute as @s[tag=target_tag]` | $O(1)$ | | `execute as @e[sort=nearest]` | $O(E\log E)=T(E+E\log E)$ | | `execute as @e[sort=nearest,limit=3]` | $O(E\log E)=T(E+E\log E+$<font color=blue>$3$</font>$)$| | `execute as @e[sort=nearest,limit=7] as @a` | $O(E\log E+P)=T(E+E\log E+$<font color=blue>$7$</font>$+$<font color=blue>$7$</font>$P)$| | `execute as @p` | $O(P)=T(P)$ | --- # 六、選擇器優化範例 以下提共幾種常見的選擇器執行時間優化技巧 --- ## 提出判斷共同項優化 主要處理:重複引用相同的選擇器項目的情況 ``` # old:a.mcfunction execute as @a[tag=target,score={object=1}] run ... execute as @a[tag=target,score={object=2}] run ... execute as @a[tag=target,score={object=3}] run ... execute as @a[tag=target,score={object=4}] run ... ``` ─── ⇓ (optimization line) ⇓ ─── ``` # new:a.mcfunction execute as @a[tag=target] run function new:b ``` ``` # new:b.mcfunction execute if entity @s[score={object=1}] run ... execute if entity @s[score={object=2}] run ... execute if entity @s[score={object=3}] run ... execute if entity @s[score={object=4}] run ... ``` ### ──────────🕝 執行時間效能分析 🕘────────── * $P$ : 玩家總數量 * $P_t$ : tag為target的玩家數量 * $C_{tag}$ : 比較tag的消耗 * $C_{sc}$ : 比較score的消耗 * $f$ : 呼叫function的消耗 old和new的時間分析以及其二者的時間差如下: * $T_\text{old}=T(4(P\cdot(C_{tag}+C_{s})))=T(4PC_{tag}+4PC_{sc})$ * $T_\text{new}=T(PC_{tag}+P_t(4C_{sc}+f))=T(PC_{tag}+4P_tC_{sc}+P_tf)$ * 時間差:$\Delta T=T_\text{new}-T_\text{old}=T(P_tf-3PC_{tag}-4C_{sc}(P-P_t))$ 整合後的判斷分支有 $k$ 條時: * $T_\text{old}=T(kPC_{tag}+kPC_{sc})$ * $T_\text{new}=T(PC_{tag}+k\cdot P_tC_{sc}+P_tf)$ * $\Delta T=T(P_tf-(k-1)PC_{tag}-k\cdot C_{sc}(P-P_t))$ > $P_t \le P$,因為有target的tag之玩家數量必定小於等於總玩家數 > $f, C_{tag}, C_{sc}$ 皆為常數,其時間複雜度為HashMap的 $O(1)$ > 當 $k$ 越多,優化的效果就越明顯 > 當 $P=P_t$ 時,其差值 $=T(P\cdot(f-(k-1)C_{tag})$,只要$f < (k-1)C_{tag}$ 即恆滿足優化 註:此結果仍可以再更優化,詳細請看[指令效能分析]() --- ###### `more about` 其餘效能分析詳細請參考另一篇Hackmd文章:[Minecraft 指令效能分析](https://hackmd.io/@mccmd-analyzed/By-kvNtUO)