在后台队列上订阅联合发布服务器时不会取消



我正试图利用Combine将D_1subscribe发送到不同队列上的上游发布服务器的功能,但我发现当我这样做时,上游发布服务器并没有正确地被取消。

订阅(on:options:(的文档提供了以下参考:

使用subscribe(on:options:(也会导致上游发布者使用指定的调度程序执行cancel((。

我并不完全清楚这句话的含义。在下面的示例代码中,我有一个符合SequenceIteratorProtocol的基本类型NameIterator。它只是模拟一个可能需要很长时间才能获取元素的自定义迭代器。

Combine将.publisher特性添加到Sequence。如果您在一个线程中订阅了该发布服务器,那么任何取消事件都会正确地传播到根发布服务器,迭代就会停止。

但是,如果调用subscribe(on:),则取消事件不会到达根发布者,直到它用完了对迭代器的调用。请注意,sink在这两种情况下都被正确调用,但迭代器仍会继续被调用,即使没有值被向下推送到管道中。

如果迭代器价格昂贵并且包含大量项目(如遍历文件系统(,就会出现问题。有没有一种方法可以正确地取消上游发布者?或者我可能错误地配置了发布者链。

样本迭代器:

struct NameIterator: Sequence, IteratorProtocol {
private let names = ["Alpha", "Beta", "Charlie", "Delta"]
private var index = 0
mutating func next() -> String? {
guard index < names.endIndex else {
return nil
}
// Simulate an expensive iterator.
sleep(1)

defer { index = names.index(after: index) }
print("NameIterator.next() called with (names[index])")
return names[index]
}
}

正确取消:

let cancellable = NameIterator().publisher
.first()
.sink { print("Sink: ($0)") }
// Outputs:
NameIterator.next() called with Alpha
NameIterator.next() called with Beta
Sink: Alpha

错误取消:

let cancellable = NameIterator().publisher
.subscribe(on: DispatchQueue(label: "BackgroundQueue"))
.first()
.sink { print("Sink: ($0)") }
// Outputs: 
NameIterator.next() called with Alpha
NameIterator.next() called with Beta
Sink: Alpha
NameIterator.next() called with Charlie  // This call was unexpected.
NameIterator.next() called with Delta    // This call was unexpected.   

文档中的引号不是关于取消的语句,而是关于线程的语句。它说:如果你订阅了某个队列,那么当/如果取消消息发送到管道上时,就会使用该队列。

通过选择订阅指定的队列,您明确表示:当取消时,将该调用排队。因此,就像对队列的任何操作一样,我们现在不知道什么时候会真正发生这种情况。声称";这个呼叫本不应该发生";因此是错误的;不存在";应该具有";故事中。相反,任何关于取消何时会渗透到发布者的期望都正是您在队列中订阅时所放弃的。

(顺便说一句,注意Completion在预期的时刻以良好的顺序到达管道——也就是说,接收器立即获得Alpha值,然后是.finishedCompletion。只有发布者才有多余的余地。(

相关内容

  • 没有找到相关文章

最新更新