什么是延缓科特林的buildSequence推荐的方法是什么?

问题描述 投票:2回答:1

我想查询分页API,并提供新的项目给用户,因为它们出现。

fun connect(): Sequence<T> = buildSequence {
    while (true) {
        // result is a List<T>
        val result = dataSource.getFirstPage()
        yieldAll(/* the new data in `result` */)

        // Block the thread for a little bit
    }
}

下面是使用范例:

for (item in connect()) {
    // do something as each item is made available
}

我首先想到的是使用delay功能,但我得到这个消息:

限制悬浮函数只能调用部件或延伸部上悬挂其限制的协程范围的功能

这是buildSequence签名:

public fun <T> buildSequence(builderAction: suspend SequenceBuilder<T>.() -> Unit): Sequence<T>

我觉得这个消息意味着我只能用在SequenceBuilder的suspend功能:yieldyieldAll和使用任意suspend函数调用是不允许的。

现在,我使用这个每次API被查询时间后阻止一秒序列建设:

val resumeTime = System.nanoTime() + TimeUnit.SECONDS.toNanos(1)
while (resumeTime > System.nanoTime()) {
    // do nothing
}

这工作,但它确实似乎并不像一个很好的解决方案。有没有人遇到过这个问题?

kotlin kotlinx.coroutines
1个回答
8
投票

Why does it not work? Some research

当我们看buildSequence,我们可以看到,它需要一个builderAction: suspend SequenceBuilder<T>.() -> Unit作为其参数。作为该方法的客户端,你就可以将手放在有suspend作为它的接收器(阅读与接收器SequenceBuilder拉姆达)一here拉姆达。 该SequenceBuilder本身标注有RestrictSuspension

@RestrictsSuspension
@SinceKotlin("1.1")
public abstract class SequenceBuilder<in T> ...

注释定义和评价是这样的:

/**
 * Classes and interfaces marked with this annotation are restricted
 * when used as receivers for extension `suspend` functions. 
 * These `suspend` extensions can only invoke other member or extension     
 * `suspend` functions on this particular receiver only 
 * and are restricted from calling arbitrary suspension functions.
 */
@SinceKotlin("1.1") @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY)
public annotation class RestrictsSuspension

由于RestrictSuspension文档讲述,在buildSequence的情况下,你可以通过一个拉姆达与SequenceBuilder为接收者,而是一个受限制的可能性,因为你只能将能够调用“在这个特别的接收器其他成员或扩展suspend功能”。这意味着,传递给buildSequence块可以呼吁SequenceBuilder定义的任何方法(如yieldyieldAll)。因为,在另一方面,该块被“从主叫任意悬浮功能受限制的”,使用delay不起作用。得到的编译器错误进行验证:

限制停止的功能只可以调用它们的受限制的协程范围构件或延伸悬浮功能。

最后,你需要知道的是,buildSequence创建一个协程是一个同步协同程序的一个例子。在你的榜样,序列代码将通过调用connect()消耗序列相同的线程中执行。

How to delay the sequence?

正如我们了解到,buildSequence创建一个同步序列。它的优良这里使用常规的线程阻塞:

fun connect(): Sequence<T> = buildSequence {
    while (true) {
        val result = dataSource.getFirstPage()
        yieldAll(result)
        Thread.sleep(1000)
    }
}

但是,你真的想要一个完整的线程被阻塞?可替代地,可以实现异步序列描述here。其结果是,使用delay和其它助悬功能将是有效的。

© www.soinside.com 2019 - 2024. All rights reserved.