iT邦幫忙

2021 iThome 鐵人賽

DAY 26
0
Software Development

Coroutine 停看聽系列 第 26

Day26:Flow 的運算子 - buffer()

Flow 是依序執行的,如果使用 collect 作為終端運算子,那麼在最後就會按照每一個元素所要花費的時間一一的執行,並把結果吐出來。

如下面的範例:

class Day25 {
    fun flow1() = flow {
        repeat(10) {
            delay(100)
            emit(it)
        }
    }
}

這個 flow 中會產生十個元素,每一個元素都需要花費 100 毫秒建立。

如果這些元素用 collect 執行的時候,也會在每一個元素上花費 200 毫秒來執行,如此一來一個元素所需要執行的時間就是 100 毫秒 + 200 毫秒,總共需要 300 毫秒。

fun main() = runBlocking {
    val day25 = Day25()
    val times = measureTimeMillis {
        day25.flow1()
            .collect {
                delay(200)
                println(it)
            }
    }

    println("$times")
}
0
1
2
3
4
5
6
7
8
9
3115
  • 在這邊我們使用 measureTimeMillis 來計算所需執行的時間。
  • 可以看到上面的結果,我們總共花費了 3115 毫秒來執行。

normal flow

Buffer 緩衝

今天要介紹的運算子 buffer 就是要在這個地方使用的,怎麼使用呢?

我們只需要在需要加上緩衝的地方使用即可,如下:

fun main() = runBlocking {
    val day25 = Day25()
    val times = measureTimeMillis {
        day25.flow1()
            .buffer() // Add here
            .collect {
                delay(200)
                println(it)
            }
    }

    println("$times")
}

我把 buffer 加在 flow 與 collect 之間,原因是每一個 flow 的元素需要 100 毫秒來產生,而執行每一個元素卻需要 200 毫秒,也就是說,如果我們在這兩個操作之間加上緩衝,那麼執行的時間應該可以減少。(因為當 collect 花費 200 毫秒處理第一筆資料時,flow 已經在建立第二筆資料了,這樣子就可以減少操作的時間。我們來實際執行一下,看看結果會是如何?

0
1
2
3
4
5
6
7
8
9
2246

經過緩衝之後,我們所需花費的時間由 3115 毫秒,減少至 2246 毫秒。提升了 27% 的速度。

buffer

其實使用 buffer 會變成使用兩個 coroutine 在執行,flow 與 collect 分別使用不同的 coroutine ,並且透過 Channel 來傳輸。

小結

在使用 Flow 時,因為是按照順序來執行,總時間就會是全部的執行時間加總起來。利用 buffer 我們就可以讓這些操作使用不同的 Coroutine,如此一來就可以同時執行多個任務,時間比沒有用 buffer 的會少很多。

參考資料

buffer

特別感謝

Kotlin Taiwan User Group

Kotlin 讀書會


上一篇
Day 25:[Android] 將 LiveData 用 Flow 替代吧
下一篇
Day27:測試 Coroutine
系列文
Coroutine 停看聽30

尚未有邦友留言

立即登入留言