在Swift中同步异步

我确定您已经遇到过异步任务,并且必须使它们同步执行的情况,因为它们之间存在依赖关系。 想象一下安排会议的场景

  • 调用一些登录API以获得令牌
  • 获取特定时间的可用人员列表
  • 得到一个人的细节
  • 与有空人员开会

在您大声疾呼这只是API的不良示例之前,请放心,我同意您的观点。 但这是我们现实太多次了。

但是,有一个开箱即用的解决方案: 在队列上 使用 操作 和链接相关任务! 这听起来像是我们要实现的教科书示例。

让我们使用操作并使其起作用:

我们可以看到我们有一个Operation SumOfTwoAsyncOperations 。 我们可以清楚地看到它的业务逻辑在全局后线程队列上的异步调用中执行业务逻辑。

这里我们有一个函数sumOfTwoAsyncOperations ,它接受4个数字,并在operation1添加number1number2operation1添加number3number4 。 我们可以看到,我们还创建了BlankOperation类型的“虚拟” operation3 BlankOperation ,其唯一目的是确认最后执行的操作,该operation3应为operation3并将消息打印到控制台中。

因此,如果现在调用此函数:

使用参数4和5,那么我们期望在控制台中获得以下输出:

运算1之和4 + 4 = 8

运算2总和5 + 5 = 10

操作2完成!

好吧..不!

我们得到这个:

操作2完成!

运算2总和5 + 5 = 10

运算1之和4 + 4 = 8

我们得到相反的顺序,但是即使那样也不能保证。 实际上,我们无法真正控制结果。 如果我们还记得本文中的讨论,则提到了依赖性管理,而其他一些操作并非完全免费或完全免费。

实际发生的事情是,我们一定会按期望的顺序启动和执行操作,但是由于它们是异步的,因此我们无法控制它们何时真正完成(即调用回调)。

信号量可以救援!

好的,如果我们使操作同步,该如何呢?

是的,为什么不? 如您所见,我们使用了信号量,这实际上是一种简单且可能是完成工作的最佳方法,特别是因为您可以设置时间限制,从而确保线程不会永远被阻塞。

永远不要使用任何技术来无限期地阻塞线程。 始终限制等待时间,确保由于某种原因任务没有完成,您的应用程序不会冻结,从而随时无响应。

永远不要阻塞主线程,考虑到依赖可能会很快发生,以至于其他地方的临时错误最终埋没了应用程序。

为了使所有这些工作正常进行,我们还需要使我们的操作异步进行并覆盖Apple文档中所述的2种标准方法:

我会说,对于某些事情来说,这是一笔相当大的工作,似乎几乎是一件微不足道的任务。 E️本质上,这就是所谓的isAsynchronous所做的是,告诉运行时在isFinished更改其值之前应用信号量(很可能是)。 似乎是一种老式的方式…

好吧,我也想探索其他可能性。


让我们看看,使用GCD且没有丑陋的嵌套时,会是什么样子:

…或者只是样板:

该代码与Operations之前的代码相同。 看起来更苗条,更易于阅读。 这绝对是我的选择。

派遣组

我们也可以对调度组执行类似的操作:

…或再次,只是样板:

我们可以看到它与之前的信号量示例没有太大区别,您还可以使用带有超时的wait (实际上我们实际上并不需要),但是我还是宁愿选择信号量,只是因为它们的目的更清晰,更适合该问题。

但是,当需要在继续之前执行一组任务并且任务没有相互依赖性时, 调度组应该始终是选择的武器。


是的,我听到了声音:使用PromiseKit可以做得更好 ! 我同意和不同意。

我爱诺言! 我喜欢在具有本机支持的语言中(例如Javascript) 。 它们将潜在的嵌套结构压平成易于阅读的闭合。 但是,如果您想在.then闭包之间传递参数,那么冷的代码会变得很丑陋。 至少直到Ecmascript 8 ,当我们得到asyncawait关键字时,这才解决了问题。

但是这些都是语言功能。 PromiseKit for Swift是一种SDK功能,可扩展类。 我用这种方法没有几个问题:

  • 永不追赶iOS SDK的故事
  • 非常强大的依赖
  • 补充语言而不是添加功能
  • 这不是Swift指导委员会倡议( Evolution )的一部分,这意味着我们不能确定过渡会迅速而轻松,并且代码肯定不会包含在语言本身中
  • 没有提供开箱即用的asyncawait关键字,但是您有Yannick提供的一个可爱的包装器来处理此问题

我可以列举更多,但我个人的观点是,与简单的GCD信号量步骤相比,所有这些都不是一个很大的优势。 至少在大多数情况下不是。

您可以下载这个简短的示例存储库并使用它,自己做判断和示例。


确实有很多解决标题问题的方法。 我个人采用简单的GCD信号量方法 ,至少直到Promises最终以其所有的美貌和力量成为Swift语言。

Interesting Posts