流-无需多次迭代即可克隆流-我做对了吗?

时间:2019-08-22 17:05:41

标签: kotlin kotlin-coroutines kotlinx.coroutines.flow

我刚刚开始熟悉Kotlin流程。

为此,我使用它们来分析二进制文件的内容,我将使用以下流程对其进行仿真:

fun testFlow() = flow {
    println("Starting loop")

    try {
        for (i in 0..5) {
            emit(i)
            delay(100)
        }

        println("Loop has finished")
    }
    finally {
        println("Finally")
    }
}

现在,我基本上需要多次文件内容来提取不同的信息集。 但是,我不想读取文件两次,而只能读取一次。

由于似乎没有内置的机制来克隆/复制流,因此我开发了以下辅助函数:

interface MultiConsumeBlock<T> {
    suspend fun subscribe(): Flow<T>
}

suspend fun <T> Flow<T>.multiConsume(capacity: Int = DEFAULT_CONCURRENCY, scope: CoroutineScope? = null, block: suspend MultiConsumeBlock<T>.() -> Unit) {
    val channel = buffer(capacity).broadcastIn(scope ?: CoroutineScope(coroutineContext))

    val context = object : MultiConsumeBlock<T> {
        override suspend fun subscribe(): Flow<T> {
            val subscription = channel.openSubscription()
            return flow { emitAll(subscription) }
        }
    }
    try {
        block(context)
    } finally {
        channel.cancel()
    }
}
然后我像这样使用

(想想与文件的类比:流a获取每条记录,流b仅获取前3条记录(=“文件头”)和流{{ 1}}标头后面的所有内容):

c

输出:

fun main() = runBlocking {
    val src = testFlow()

    src.multiConsume {
        val a = subscribe().map { it }
        val b = subscribe().drop(3).map{ it + it}
        val c = subscribe().take(3).map{ it * it}

        mapOf("A" to a, "B" to b, "C" to c).map { task -> launch { task.value.collect{ println("${task.key}: $it")} } }.toList().joinAll()
    }
}

到目前为止看起来不错。 但是,我不确定在这方面是否正确使用Kotlin的流程。
我会为死锁,错过异常等打开自己的大门吗?

The documentation just states

  

Flow接口的所有实现都必须遵循以下详细描述的两个关键属性:

     
      
  • 上下文保护。
  •   
  • 异常透明性。
  •   

但是我不确定我的实现是这种情况还是缺少某些东西。
或者也许有更好的方法在一起?

0 个答案:

没有答案