Concurrency in iOS is a massive topic. So in this article I want to zoom in on a sub-topic concerning queues and the Grand Central Dispatch (GCD) framework.

iOS中的并发性是一个巨大的话题。 因此,在本文中,我想放大有关队列和中央中央调度(GCD)框架的子主题。

In particular, I wish to explore the differences between serial and concurrent queues, as well as the differences between synchronous and asynchronous execution.

特别是,我希望探讨串行队列和并发队列之间的差异,以及同步和异步执行之间的差异。

If you've never used GCD before, this article is a great place to start. If you have some experience with GCD, but are still curious about the topics mentioned above, I think you will still find it useful. And I hope you will pick up one or two new things along the way.

如果您以前从未使用过GCD,那么本文是一个不错的起点。 如果您对GCD有一定的经验,但是仍然对上述主题感到好奇,那么我认为您仍然会发现它很有用。 我希望您在此过程中能学到一两个新事物。

I created a SwiftUI companion app to visually demonstrate the concepts in this article. The app also has a fun short quiz that I encourage you to try before and after reading this article. Download the source code here, or get the public beta here.

我创建了一个SwiftUI配套应用,以直观地演示本文中的概念。 该应用程序还提供了一个有趣的简短测验,我鼓励您在阅读本文之前和之后进行尝试。 在此处下载源代码 ,或在此处获取公开Beta 。

I will begin with an introduction to GCD, followed by a detailed explanation on sync, async, serial and concurrent. Afterwards, I will cover some pitfalls when working with concurrency. Finally, I will end with a summary and some general advice.

我将先介绍GCD,然后再详细介绍同步,异步,串行和并发。 之后,在并发工作时,我将介绍一些陷阱。 最后,我将以总结和一些一般性建议作为结尾。

介绍 (Introduction)

Let’s start with a brief intro to GCD and dispatch queues. Feel free to skip to the Sync vs Async section if you are already familiar with the topic.

让我们从GCD和调度队列的简要介绍开始。 如果您已经熟悉该主题,请随时跳至“ 同步与异步”部分。

并发和中央调度 (Concurrency and Grand Central Dispatch)

Concurrency lets you take advantage of the fact that your device has multiple CPU cores. To make use of these cores, you will need to use multiple threads. However, threads are a low-level tool, and managing threads manually in an efficient manner is extremely difficult.

并发使您可以利用设备具有多个CPU内核的优势。 要使用这些核心,您将需要使用多个线程。 但是,线程是低级工具,以高效方式手动管理线程非常困难。

Grand Central Dispatch was created by Apple over 10 years ago as an abstraction to help developers write multi-threaded code without manually creating and managing the threads themselves.

Apple于10年前创建了Grand Central Dispatch,它是一种抽象,可帮助开发人员编写多线程代码,而无需自己手动创建和管理线程。

With GCD, Apple took an asynchronous design approach to the problem. Instead of creating threads directly, you use GCD to schedule work tasks, and the system will perform these tasks for you by making the best use of its resources. GCD will handle creating the requisite threads and will schedule your tasks on those threads, shifting the burden of thread management from the developer to the system.

通过GCD,Apple采用了异步设计方法 解决问题。 您可以使用GCD安排工作任务,而不必直接创建线程,系统将通过充分利用其资源来为您执行这些任务。 GCD将处理创建必要的线程,并将您的任务安排在这些线程上,从而将线程管理的负担从开发人员转移到系统上。

A big advantage of GCD is that you don’t have to worry about hardware resources as you write your concurrent code. GCD manages a thread pool for you, and it will scale from a single-core Apple Watch all the way up to a many-core MacBook Pro.

GCD的一大优点是,您在编写并发代码时不必担心硬件资源。 GCD为您管理线程池,它将从单核Apple Watch一直扩展到多核MacBook Pro。

调度队列 (Dispatch Queues)

These are the main building blocks of GCD which let you execute arbitrary blocks of code using a set of parameters that you define. The tasks in dispatch queues are always started in a first-in, first-out (FIFO) fashion. Note that I said started, because the completion time of your tasks depends on several factors, and is not guaranteed to be FIFO (more on that later.)

这些是GCD的主要构建块,可让您使用定义的一组参数执行任意代码块。 调度队列中的任务始终以先进先出(FIFO)的方式启动。 请注意,我说的是start ,因为您的任务的完成时间取决于几个因素,并且不能保证是FIFO(稍后会详细介绍)。

Broadly speaking, there are three kinds of queues available to you:

从广义上讲,您可以使用三种队列:

  • The Main dispatch queue (serial, pre-defined)主调度队列(串行,预定义)
  • Global queues (concurrent, pre-defined)全局队列(并发,预定义)
  • Private queues (can be serial or concurrent, you create them)专用队列(可以创建串行队列,也可以并发队列)

Every app comes with a Main queue, which is a serial queue that executes tasks on the main thread. This queue is responsible for drawing your application’s UI and responding to user interactions (touch, scroll, pan, etc.) If you block this queue for too long, your iOS app will appear to freeze, and your macOS app will display the infamous beach ball/spinning wheel.

每个应用程序都带有一个主队列,它是一个在主线程上执行任务的串行队列。 此队列负责绘制应用程序的UI并响应用户交互(触摸,滚动,平移等)。如果您阻塞此队列的时间过长,iOS应用程序将似乎死机,而macOS应用程序将显示臭名昭著的海滩球/纺车。

When performing a long-running task (network call, computationally intensive work, etc), we avoid freezing the UI by performing this work on a background queue. Then we update the UI with the results on the main queue:

在执行长时间运行的任务(网络调用,计算密集型工作等)时,我们通过在后台队列上执行此工作来避免冻结UI。 然后,我们使用主队列上的结果更新UI:

As a rule of thumb, all UI work must be executed on the Main queue. You can turn on the Main Thread Checker option in Xcode to receive warnings whenever UI work gets executed on a background thread.

根据经验,所有UI工作都必须在Main队列上执行。 您可以在Xcode中打开“主线程检查器”选项,以在UI工作在后台线程上执行时接收警告。

In addition to the main queue, every app comes with several pre-defined concurrent queues that have varying levels of Quality of Service (an abstract notion of priority in GCD.)

除了主队列之外,每个应用程序还带有几个预定义的并发队列,这些队列具有不同级别的服务质量 (GCD中优先级的抽象概念)。

For example, here’s the code to submit work asynchronously to the user interactive (highest priority) QoS queue:

例如,下面是将工作异步提交到用户交互式 (最高优先级)QoS队列的代码:

DispatchQueue.global(qos: .userInteractive).async {print("We're on a global concurrent queue!")
}

Alternatively, you can call the default priority global queue by not specifying a QoS like this:

或者,您可以通过不指定以下QoS来调用默认优先级全局队列:

Additionally, you can create your own private queues using the following syntax:

此外,您可以使用以下语法创建自己的专用队列:

When creating private queues, it helps to use a descriptive label (such as reverse DNS notation), as this will aid you while debugging in Xcode’s navigator, lldb, and Instruments:

创建专用队列时,使用描述性标签(例如反向DNS表示法)会有所帮助,因为在Xcode的导航器,lldb和Instruments中进行调试时,这将为您提供帮助:

By default, private queues are serial (I’ll explain what this means shortly, promise!) If you want to create a private concurrent queue, you can do so via the optional attributes parameter:

默认情况下,私有队列是串行的 (稍后,我会解释,这是什么意思,诺言!)如果要创建私有并发队列,可以通过可选的attributes参数来实现:

let concurrent = DispatchQueue(label: "com.besher.serial-queue", attributes: .concurrent)
concurrent.sync {print("Private concurrent queue")
}

There is an optional QoS parameter as well. The private queues that you create will ultimately land in one of the global concurrent queues based on their given parameters.

也有一个可选的QoS参数。 您创建的专用队列最终将根据其给定参数进入全局并发队列之一。

任务是什么? (What’s in a task?)

I mentioned dispatching tasks to queues. Tasks can refer to any block of code that you submit to a queue using the sync or async functions. They can be submitted in the form of an anonymous closure:

我提到了将任务调度到队列。 任务可以引用您使用syncasync函数提交到队列的任何代码块。 它们可以以匿名闭包的形式提交:

DispatchQueue.global().async {print("Anonymous closure")
}

Or inside a dispatch work item that gets performed later:

或在稍后执行的调度工作项中:

Regardless of whether you dispatch synchronously or asynchronously, and whether you choose a serial or concurrent queue, all of the code inside a single task will execute line by line. Concurrency is only relevant when evaluating multiple tasks.

无论您是以同步方式还是异步方式调度,还是选择串行队列还是并发队列,单个任务中的所有代码都将逐行执行。 并发仅在评估多个任务时才有意义。

For example, if you have 3 loops inside the same task, these loops will always execute in order:

例如,如果在同一任务中有3个循环,则这些循环将始终按顺序执行:

DispatchQueue.global().async {for i in 0..<10 {print(i)}for _ in 0..<10 {print("												

并发说明:如何构建多线程iOS应用相关推荐

  1. 浅析C#中构建多线程应用程序

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  2. Java的并发编程中的多线程问题到底是怎么回事儿?

    转载自   Java的并发编程中的多线程问题到底是怎么回事儿? 在我之前的一篇<再有人问你Java内存模型是什么,就把这篇文章发给他.>文章中,介绍了Java内存模型,通过这篇文章,大家应 ...

  3. python并发编程之semaphore(信号量)_Python 并发编程系列之多线程

    Python 并发编程系列之多线程 2 创建线程 2.1 函数的方式创建线程 2.2 类的方式创建线程 3 Thread 类的常用属性和方法 3.1 守护线程: Deamon 3.2 join()方法 ...

  4. ios apple语音性别_如何使用Apple的CoreML和Vision API构建图像识别iOS应用

    ios apple语音性别 by Mark Mansur 马克·曼苏尔(Mark Mansur) 如何使用Apple的CoreML和Vision API构建图像识别iOS应用 (How to buil ...

  5. Python并发编程系列之多线程

    1 引言 上一篇博文详细总结了Python进程的用法,这一篇博文来所以说Python中线程的用法.实际上,程序的运行都是以线程为基本单位的,每一个进程中都至少有一个线程(主线程),线程又可以创建子线程 ...

  6. 【Java并发编程】Java多线程(四):FutureTask 源码分析

    前言:[Java并发编程]Java多线程(三):Runnable.Callable --创建任务的方式 在上一篇文章的末尾我们通过两个问题,引出了 FutureTask 及其设计思路,先来回顾一下: ...

  7. IOS开发系列之阿堂教程:构建开发IOS应用的虚拟机开发环境实践

    说到IOS的开发,不能不说 到一个问题,如何配置和构建一个IOS的开发环境!我下面要说的主要是针对没有MAC Apple机的网友,如何安装和配置一个属于自己的IOS开发环境.如果已经有MAC 苹果机的 ...

  8. 【面试:并发篇09:多线程:interrupt 方法详解】

    [面试:并发篇09:多线程:interrupt 方法详解] 00.前言 如果有任何问题请指出,感谢. 01.介绍 程序中,有些线程的中断需要外部干预,比如线程中存在while(true)循环,或者存在 ...

  9. java多线程与并发_漫画 | Java多线程与并发(一)

    1.什么是线程? 2.线程和进程有什么区别? 3.如何在Java中实现线程? 4.Java关键字volatile与synchronized作用与区别? volatile修饰的变量不保留拷贝,直接访问主 ...

最新文章

  1. 【每日一算法】使用二分法解决x 的平方根问题
  2. 【前沿技术】2021年AI将改变制造业的6大应用趋势
  3. codeforces 501 C,D,E
  4. 在VC++中创建DLL文件并加载
  5. CSS元素高度塌陷的几种常见解决办法!
  6. C语言位于30到100之间的一个奇数,《帮你度过C语言新手阶段》系列之三
  7. 前端学习(1173):两种字符串方法
  8. 数据增强 transform_深度学习-Pytorch框架学习之数据处理篇
  9. 对HTTP基本认识(HTTP协议入门必备)
  10. 匿名内部类 handler
  11. 字符串转换成json的三种方式
  12. 《剑指Offer》 调整数组顺序使奇数位于偶数前面
  13. php正则表达式 包含特殊字符,php正则表达式的特殊字符含义
  14. OpenCV图像处理基础(变换和去噪)
  15. 周星驰八级全国统一试卷
  16. Luogu5607 [Ynoi2013] 无力回天 NOI2017
  17. Lua,LuaJIT,Luarocks的安装与配置-史上最详细【Linux】
  18. k8s集群的搭建-云服务器
  19. 高职计算机网络基础说课,《计算机网络》说课课件.ppt
  20. Android音频开发(二):录制音频(WAV及MP3格式)

热门文章

  1. 数组的操作与方法的操作 0303 2101
  2. 存储与硬盘挂载 200305
  3. django-模板过滤器
  4. Algs4-1.3.33矩阵库
  5. 连载13:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)...
  6. 货车运输 vijos 1843 NOIP2013 D1T3 最大生成树,并查集,(伪·LCA)
  7. 利用iTextSharp填写中文(中日韩)PDF表单(完整解决方案)
  8. Spring Session 2.0.0.M1 发布,分布式解决方案
  9. scala学习手记5 - 元组与多重赋值
  10. ext/iconv/.libs/iconv.o: In function `_php_iconv_strlen'