iT邦幫忙

2023 iThome 鐵人賽

DAY 24
0

本日主題 - Item 47: 避免非必要的物件創建

建立物件的代價

物件的建立總是需要某些代價的,有時可能很昂貴。這就是為什麼避免不必要的物件建立可以是一個重要的優化方法。這可以在許多層面上完成。例如,在 JVM 中,保證了一個同樣字串在同一虛擬機上運行時都是唯一的,有一個字串池。這也間接的讓 == === 是相同的。

val str1 = "Lorem ipsum dolor sit amet"
val str2 = "Lorem ipsum dolor sit amet"
print(str1 == str2) // true
print(str1 === str2) // true

用工廠模式作快取

每次我們使用建構子時,我們都會建立一個新的物件,但當我們使用工廠函數時,這不一定是真的,因為它們可以有一個快取。最簡單的情況是工廠函數始終返回相同的物件。例如,這是 stdLib 中的 emptyList 的實現:

fun <T> emptyList(): List<T> = EmptyList

有時我們有一組物件,我們根據參數返回其中之一。例如,Kotlin 協程中的 Dispatchers.Default 擁有一個執行緖池;每當我們使用預設調度器開始任何操作時,他會在池中找到未被使用的執行緒來啟動。對於帶參數的工廠函數,也可以進行快取。在這種情況下,我們可能會在 Map 中保留我們的物件:

private val connections: MutableMap<String, Connection> =
    mutableMapOf<String, Connection>()

fun getConnection(host: String) =
    connections.getOrPut(host) { createConnection(host) }

這種方式可以有效地避免重複的計算,並提高程式的性能。不過要注意這是用空間換取時間,需要一些策略來控制快取的數量。這是常見的 pattern, 因此,我們可引入快取的函式庫

快取函式庫 Caffeine 與 Aedile

Caffeine

Caffeine 是 Java Cache 中的後起之秀,提供了更高的性能和更多的功能。

使用 Caffeine 的來建立一個快取:

val cache = Caffeine.newBuilder()
    .maximumSize(1000)             // 設定最大容量
    .expireAfterWrite(5, TimeUnit.MINUTES) // 設定寫入後5分鐘到期
    .build<String, String>()

加入和取得資料

cache.put("key1", "value1")
val value = cache.getIfPresent("key1")

使用 get 或 getOrLoad 來進行取值或加載:

val value = cache.get("key2") { computeValueForKey(it) }

Caffeine 還提供了更多高階功能,例如大小策略、刷新策略、監聽器等。

Aedile 支援 suspend function

Aedile 是一個針對 Kotlin 協程的快取庫,主要封裝了 Caffeine。它提供了對 Kotlin 協程的原生支援,可以更直接與 suspend function 整合。

以下是如何使用 Aedile 來快取 suspend function 的結果:

val cache = caffeineBuilder<String, FruityVice> {
  expireAfterWrite = 5.toDuration(DurationUnit.MINUTES)
}.build { findByName(it) }
 
// expensive call
private suspend fun findByName(name: String) = 
 
suspend fun findByNameWithCache(name: String) = 
    cache.get(name)
 

當你第一次調用 findByNameWithCache 時,它會實際調用 findByName 並將結果儲存在快取中。之後的調用會直接從快取中獲取結果,除非該結果已超過時間(5分鐘)被清出。

Dropbox 開源的 Store

這是 mobile 開發者推薦的另一個快取函式庫叫 store, 概念會是差不多,大家也是可以參考看看。

https://mobilenativefoundation.github.io/Store/

每日一推(G)I-DLE

TOMBOY 舞台真的很炸

Yes


上一篇
D23: Effective Kotlin 第三部分 - 效率優化
下一篇
D25: Kotlin 效能 - 重物件挪抬與 Lazy 延遲初始化
系列文
讓 Kotlin 程式碼更道地 - 談 Effective Kotlin 與相關的 Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言