在本书的这一部分中,您将学习并发的基础知识。你会学到它是什么,它能解决什么问题,你为什么要用它?
此外,您将了解并发在iOS开发中所包含的基本部分:Grand Central Dispatch
和Operations
。
本节将为您提供有关并发性的基本知识,所以请务必通读!接下来的部分将分别更深入地讨论这些概念。
第1章:引言:快速了解并发性是什么,以及为什么你可能想要使用它。
第2章:GCD vs Operations
:GCD vs Operations:并发可以通过Grand Central Dispatch
(GCD
)或操作来处理。了解两者之间的区别以及为什么你会选择其中一种。
第一章节:介绍
性能、响应性。它们不是性感的任务。如果处理得当,没有人会感谢你。如果操作不当,应用程序的留存率将会下降,你会在下一次的年度绩效评估中被淘汰。
在速度、性能和总体响应能力方面,应用程序可以通过多种方式进行优化。这本书将关注并发的主题。
1.1 并发性是什么?
维基百科将并发性定义为“将程序、算法或问题分解为顺序无关或部分顺序的组件或单元的可分解性属性”。这意味着查看应用程序的逻辑,以确定哪些部分可以同时运行,并且可能以随机的顺序运行,但仍然可以得到正确的数据流实现。
现代设备几乎总是有一个以上的CPU,苹果的iphone自2011年以来一直是双核的。拥有多个核心意味着它们能够同时运行多个任务。通过将应用程序分割成逻辑“块”代码,iOS设备可以同时运行程序的多个部分,从而提高整体性能。
1.2 为什么使用并发?
确保您的应用程序尽可能平稳地运行是非常重要的,并且终端用户永远不会被迫等待某些事情发生。对于大多数与计算机无关的事情来说,一秒钟是非常短的时间。然而,如果一个人在像iPhone这样的设备上做了一个动作后,需要等待一秒钟才能看到响应,那感觉就像漫长的等待一样。“它太慢了”是导致你的应用被卸载的主要原因之一。
在图像表中滚动是终端用户会因缺乏并发性而受到影响的一种比较常见的情况。如果您需要从网络下载一个图像,或者在显示它之前执行某种类型的图像处理,滚动将会中断,您将被迫显示多个“繁忙”指示器而不是预期的图像。
使用并发的一个好处是,它可以帮助您花更多的时间考虑应用程序的总体架构。你会发现自己不再只是编写大量的方法来“完成工作”,而是自然地编写更小的、更易于管理的、可以并发运行的方法。
1.3 如何使用并发性
这就是这本书的重点!在高层次上,您需要构建您的应用程序,以便一些任务可以同时运行。修改同一资源的多个任务(例如。不能同时运行,除非您使它们线程安全。
访问不同资源或只读共享资源的任务都可以通过不同的线程访问,从而实现更快的处理。
本书将关注iOS为您提供并发运行代码能力的两种主要方式。关于Grand Central分派的第一部分将介绍一些常见场景,您将发现自己能够实现并发性。您将学习如何在后台运行任务,如何将任务分组,以及如何处理可以同时运行的任务数量的限制。在第一部分结束时,您还将对并发性的危险以及如何避免它们有一个深刻的理解。
在第二部分中,您将关注Operation
类。构建在中央调度之上的操作允许处理更复杂的场景,比如在后台线程上运行可重用代码,让一个线程依赖于另一个线程,甚至在操作启动或完成之前取消操作。
大多数现代编程语言都提供了某种形式的并发性,Swift当然也不例外。不同的语言使用不同的机制来处理并发性。例如,c#和Typescript使用异步/等待模式,而Swift使用闭包来处理在另一个线程上运行的内容。Swift 5最初计划实现更常见的异步/等待模式,但它被从规范中删除,直到下一个版本。
1.4 从这里到哪里去?
好的,当然到下一页!希望当你读完下面几章的时候,你会对并发可以为你的应用程序做什么以及为什么你的终端用户会欣赏你为使应用程序尽可能快地执行所付出的额外努力有一个认识。在应用程序生命周期的早期,知道什么时候使用Grand Central Dispatch
而不是Operation
子类,将节省您在开发过程中重复工作的时间。
第二章节: GCD & Operations
在并发应用程序时,您将使用两个api: Grand Central Dispatch
(通常称为GCD
)和Operations
。这些既不是相互竞争的技术,也不是你只能在两者之间选择的东西。事实上,Operations
是建立在GCD
之上的!
2.1 Grand Central Dispatch
GCD是苹果对C语言libdispatch
库的实现。它的目的是将任务(方法或闭包)排队,根据资源的可用性,这些任务可以并行运行;然后它在一个可用的处理器内核上执行这些任务。
注意:苹果的文档有时会用
block
代替closure
,因为这是Objective-C
中使用的名称。您可以认为它们在并发的上下文中是可互换的。
虽然GCD
在其实现中使用线程,但作为开发人员,您不需要担心自己管理线程。GCD的任务非常轻,以至于苹果在2009年的GCD技术简报中说,实现GCD只需要15条指令,而创建传统的线程可能需要几百条指令。
GCD为您管理的所有任务都放在GCD管理的先进先出(FIFO)队列中。提交给队列的每个任务都将在系统完全管理的线程池中执行。
注意:不能保证任务将针对哪个线程执行
2.1.1 同步异步任务
放置在队列中的工作可以同步运行,也可以异步运行。当同步运行一个任务时,您的应用程序将等待并阻塞当前的运行循环,直到执行结束,然后再转移到下一个任务。或者,异步运行的任务将启动,但立即返回应用程序的执行。通过这种方式,应用程序可以在执行第一个任务时自由地运行其他任务
注意:重要的是要记住,虽然队列是基于FIFO的,但这不能确保任务按照提交的顺序完成。FIFO过程适用于任务开始时,而不是任务结束时。
通常,你会想要接受任何你能找到的长时间运行的非ui任务,并让它在后台异步运行。GCD通过闭包和几行代码使这变得非常简单,如下所示:
// Class level variable
let queue = DispatchQueue(label: "com.raywenderlich.worker")
// Somewhere in your function
queue.async {
// Call slow non-UI methods here
DispatchQueue.main.async {
// Update the UI here
}
}
您将在第3章“队列和线程”中学习所有关于DispatchQueue
的内容。通常,您创建一个队列,向它提交一个任务以在后台线程上异步运行,完成后,将代码委托回主线程以更新UI。
2.1.2 串行和并发队列
任务提交到的队列也具有串行或并发的特征。串行队列只有一个与之关联的线程,因此在任何给定时间只允许执行一个任务。另一方面,并发队列能够利用系统拥有的所有线程。线程将根据需要在并发队列上创建和释放。
注意:虽然你可以告诉iOS你想使用一个并发队列,但记住,不能保证一次运行多个任务。如果你的iOS设备完全陷入困境,你的应用程序正在争夺资源,它可能只能运行一个任务。
虽然最初的区别看起来很微妙,但仅仅因为任务是异步的并不意味着它们将并发运行。实际上,您可以向串行队列或并发队列提交异步任务。同步或异步只是标识运行任务的队列是否必须等待任务完成后才能产生下一个任务。
另一方面,将某个对象分类为串行还是并发,可以识别该队列是有一个线程可用还是有多个线程可用。如果你仔细想想,向一个串行队列提交三个异步任务意味着每个任务必须在下一个任务能够开始之前完全完成,因为只有一个线程可用。
换句话说,一个任务是同步的还是不同步的都与任务的源对话。串行或并发与任务的目标通信
2.2 Operations
GCD对于需要在后台运行一次的常见任务来说非常棒。当您发现自己正在构建应该可重用的功能时——比如图像编辑操作——您可能希望将该功能封装到一个类中。通过子类化Operation,您可以实现这个目标!
2.2.1 Operation subclassing
Operation
是完全功能的类,可以提交给操作队列,就像你提交一个工作闭包给GCD的DispatchQueue
一样。因为它们是类并且可以包含变量,所以您可以知道操作在任何给定点的状态。
操作可以以下列任何状态存在:
- isReady
- isExecuting
- isCancelled
- isFinished
与GCD不同,操作在默认情况下是同步运行的,让它异步运行需要做更多的工作。虽然您可以自己直接执行操作,但由于其同步特性,这几乎不是一个好主意。您将希望通过将它提交到一个OperationQueue
来将它从主线程中删除,这样UI性能就不会受到影响。
2.2.2 额外的功能
但是等等,还有更多!操作提供了对任务的更大控制,因为您现在可以处理诸如取消任务、报告任务状态、将异步任务包装到操作中以及指定不同任务之间的依赖性等常见需求。第6章,Operations
,将提供在应用程序中使用操作的更深入的讨论。
2.2.3 BlockOperation
有时候,你会发现自己在开发一个大量使用操作的应用程序,但却需要一个更简单的、类似gcd的闭包。如果您不想也创建一个DispatchQueue
,那么您可以使用BlockOperation
类。
BlockOperation
子类为您创建操作,并管理一个或多个闭包在默认全局队列上的并发执行。但是,作为一个实际的Operation
子类,您可以利用操作的所有其他特性。
注意:块操作并发运行。如果需要它们串行运行,则需要设置一个分派队列。
2.3 “你应该用哪一种?”
对于你应该在应用程序中使用GCD还是操作,并没有明确的指示。对于你只需要执行和忘记的简单任务,GCD更容易使用。当您需要跟踪作业或维护取消作业的能力时,操作提供了更多的功能。
如果您只是处理需要执行的方法或代码块,那么GCD是一个合适的选择。如果您使用的对象需要封装数据和功能,那么您更有可能使用Operations
。一些开发人员甚至极端地说,你应该总是使用Operations
,因为它是建立在GCD之上的,而苹果的指导说,总是使用提供的最高级别的抽象。
在一天结束的时候,你应该使用在那个时候最有意义的技术,并且为你的项目或者特定的用例提供最大的长期可持续性。
在下一章中,您将深入了解Grand Central Dispatch
是如何工作的,了解线程和队列之间的区别,并确定在应用程序中实现并发时可能出现的一些复杂性。
2.4 从这里到哪里去
当然是翻到下一章了!本书的其余部分将详细介绍中央调度和操作。当你读完这本书的时候,你会对这两种选择都有一个坚实的了解,也会对如何选择其中一种有一个更好的想法。