我们如何通过使用主队列来避免线程问题

有时,问题的最佳解决方案是根本不解决所有问题,这对于编程来说尤其如此。 多线程是一个有很多陷阱的方面。 这不仅是理解多线程及其工作方式的问题,而且还因为我们不了解底层系统或硬件的工作情况而导致错误如何蔓延。

但是,这些问题并不需要每次都解决。 如果我们的约束允许,我们可以简单地避免使用它们,而对于GCD而言,更是如此,我们可以利用队列来完成工作。 在NoctaCam,我们尝试将大多数代码保留在mainQueue中,并使用许多技巧来避免使用其他队列。 这并不是说我们在性能或用户体验上有所妥协,但我们意识到我们根本不需要这样做。 这篇文章是关于我们如何做的。

首先,将代码放入主队列的优点:

调试:如果要从拥有单线程代码的所有优点中选择一个,这将是最重要的因素。 如果可以容易地预测程序的状态和执行流程,则调试很容易。

更快的开发:在启动环境中,我们需要快速构建,快速推送和迭代。 多线程问题阻碍了开发速度和发布周期。

更简单的代码:任何编写多线程代码的人都知道,要使其正常工作,还需要多少额外的代码。 团队成员尝试避免使用其他成员编写的代码,因为锁和其他同步原语使其难以阅读和理解。

那么我们该怎么做呢?

通过尽可能利用GCD API。 通过在主队列中运行所有代码并不意味着并行性和性能受到损害。 可以以并行化的方式编写代码的瓶颈,但不会削弱代码的其他方面。 例如:

这是map函数的一个版本,它并行执行处理,但同步返回结果,从而在代码的关键方面提高了性能。

对于可以异步运行的代码,不要使用后台队列,只需将其异步提交到主队列即可。 您可以使用以下包装器功能:

假定它们不再长时间运行,那么在程序执行过程中在后台重复执行的任务也可以在主队列中完成:

只需将异步重复提交同一任务到mainQueue即可,但要有一些延迟。 这看起来像递归,但并非如此,因为updateUI函数在将自身提交给mainQueue之后每次都会返回。

NSNotifications和KVO调用需要注意。 不能依靠他们被主队列调用。 另外,有几种iOS方法的回调在任意的后台队列中返回。 因此,当文档说它将在后台队列中或不清楚时,请跳至主队列。

陷阱

当然,这不是灵丹妙药,我们需要添加一些监视以记录是否有任何任务花费很长时间,这可能会阻塞主队列。 在处理主队列时,唯一需要遵循的规则是在任何情况下都不应阻止它。 这意味着不能对主队列进行任何实时处理。