并发运行大量异步操作可能导致线程爆炸,并经常导致崩溃。最好限制活动操作的数量,以便并发队列不会在其他线程等待时创建额外的线程。使用带有maxConcurrentOperationCount的OperationQueue将限制操作的数量。Apple的BlockOperation不会异步运行,而此实现会异步运行,并且isAsynchronous设置为 true。
自从 iOS 2.0 首次向开发者提供 SDK 时,Apple 就包含了 OperationQueue。它早于 iOS 4.0 中包含的 Dispatch (即 Grand Central Dispatch)。它添加了更多并发功能,以取代经典的线程编程技术,目标是调整为平台编写的代码,以便运行时队列可以处理 Apple 在未来几年内从 2 核增加到更多核心的工作。 使用带有 OperationQueue 的 Operation 仍然有很多优点。 一个关键的优势是设置 maxConcurrentOperationCount 来限制并发任务的数量。 使用 Dispatch,要么工作以串行方式运行(一次一个),要么并发运行且没有限制。
一个 Operation
可以具有依赖关系,这些依赖关系是其他操作。 可以根据需要设置一系列操作以支持正在完成的工作,并在设置了最大值的 OperationQueue
上运行它。
Apple 在 iOS 13.0 和所有其他 Apple 平台上推出了 Combine。 它支持发布者 (Publishers) 和订阅者 (Subscribers),它们可以使用一种称为反压 (back pressure) 的技术动态控制正在完成的工作量。 不是具有固定限制,而是可以在处理运行时更改 Demand
。
运行异步操作需要管理状态转换。 操作有 4 种状态:就绪 (ready)、执行中 (executing)、已完成 (finished) 和已取消 (cancelled)。 状态的更改通过 KVO 报告,这是一种非常有效的机制。异步与同步操作涵盖了如何处理这些状态转换。
但是,如果您手动执行操作,您可能希望将操作对象定义为异步的。 定义异步操作需要更多的工作,因为您必须监视任务的持续状态并使用 KVO 通知报告该状态的更改。 但是,在您希望确保手动执行的操作不会阻塞调用线程的情况下,定义异步操作非常有用。
在此代码中,KVO 更改由 transition(to:)
函数处理,同时可以提供一个闭包,该闭包将被赋予一个 done
闭包。 一旦完成异步工作,就应该使用该闭包。 它将触发状态转换为 .finished
,以便 OperationQueue 知道该操作已完成,并且可以启动另一个操作。 除了限制并发操作的数量之外,这种机制还允许随时将操作添加到队列中。
每个状态转换都涉及 2 个状态,它们由计算属性表示。 当操作开始时,isReady
和 isExecuting
都会发生变化。 稍后,当调用 done()
闭包时,isExecuting
和 isFinished
会发生变化,因此 transition(to:)
函数会为 newState
和 state
调用 willChangeValue
和 didChangeValue
。 OperationQueue 可以观察到这些变化并立即做出反应,因为 KVO 非常有效。
对于异步操作,只覆盖了 start
函数,而没有覆盖 main
函数,正如文档中所述。 异步工作将在 start
函数中启动,并在完成后将状态转换为已完成。
就像 cancel 函数 在 DispatchWorkItem 上一样,在操作上调用 cancel
函数不会停止已启动的操作。 如果已排队的操作在启动之前被取消,它将阻止该操作启动。
取消会导致将来尝试执行工作项的操作立即返回。 取消不会影响已经开始执行的工作项的执行。