Tag: 多线程

使用Grand Central Dispatch进行并行计算和编程

我们将使用原生的Grand Central Dispatch( GCD )框架研究iOS上Swift的并发编程。 如果您不熟悉并发编程,建议您先看一下Wikipedia。 让我们开始研究此API背后的哲学和良好实践。 GCD (Grand Central Dispatch)是一个框架,提供低级API来处理iOS,macOS,tvOS和watchOS平台上的并发编程。 苹果公司提供竞争管理的所有更高级别的框架(例如NSOperation )都基于GCD 。 这些API允许您将流程的工作划分为各个任务,然后使用队列帮助协调并行或顺序执行这些任务。 它使我们能够从线程,处理器或核心的概念中抽象出来,并同时利用其自己的线程池来优化资源管理。 GCD所基于的基本概念是FIFO(先进先出)。 我们要执行的任务将首先插入到这些队列中,然后GCD将单独检索它们,以将它们分派到正确的线程/处理器/心脏。 我们可以区分两种文件: 并发文件:并行执行多个任务 顺序或串行 文件:连续执行一对一的任务 这是现有文件的3类: Main queue :等同于主要处理应用程序UI的主线程。 所有UI调用都必须在此队列上完成。 Global queue :系统为我们提供3个具有不同优先级(高,默认和低)的全局尾部。 这3个文件是Concurrent类型的。 Custom queue :可以手动创建并具有所需类型(串行或并发)的队列。 让我们从创建3个队列类别之一开始: 为了创建自定义队列 ,我们首先定义一个标识符(建议使用反向DNS格式)。 现在我们知道了如何创建文件,如何使用它们? 非常简单,这要感谢“调度员”! 这是一个小例子: 让我们分解所有这些。 我们开始创建低优先级队列。 然后,我们在先前恢复的低优先级队列上异步“分发”代码块。 该代码块异步获取数据以将其存储在data变量中。 最后,我们使用恢复的数据更新主线程中的view 。 在主线程中执行最后一步非常重要,因为UIKit不是线程安全的,并且如果您在另一个线程中更新组件,则应用程序可能崩溃或具有未定义的行为。 控制台将在此处显示: 之前 后 内部异步块 在主队列块内 完蛋了! 使用GCD您可以管理所有有关并发编程的问题。 在本节中,我们将进一步介绍不同的使用情况。 […]

适用于初学者的iOS多线程策略

并发是编程中最复杂的(读作“ 吓人” )主题之一。 这是一个非常强大的工具,可以为您的应用程序带来魔力。 但是,如果使用不当,还会带来讨厌的问题。 作为iOS的初级程序员,如果不知道如何挥动这把双刃剑,就无法改善。 今天,我将帮助您在iOS中使用多线程。 什么是线程? Apple的文档将线程定义为“一种在应用程序内部实现多个执行路径的相对轻量级的方法。”为了简化起见,您可以想象每个线程都是一个cookie怪物,每个cookie怪物都有自己的cookie队列(代码等待执行)。 多线程很棒。 iOS要求在主线程中执行与UI相关的代码。 将UI代码想象成M&M cookie; 因此,所有M&M Cookie只能进入主要Cookie怪物。 如果我们只有一个Cookie怪兽,其中包含许多种Cookie(用于UI的M&M,用于网络连接的巧克力芯片等),那么M&M Cookie的执行速度将非常慢,因为其他Cookie太多了。 我们会看到该应用程序的响应速度不太快,甚至会冻结,因为主要怪物无法足够快地进入M&M Cookie。 采用并发就像让多个饼干怪兽吃饼干一样。 如果您可以指定一个怪物只吃巧克力(网络处理)饼干,一个怪物只吃花生酱(数据存储和缓存)饼干,并且仅将M&M(UI)饼干喂给主要的饼干怪物,那么所有饼干将以更快,更清洁的方式被食用。 这就是多个线程如何提高应用程序性能的方式。 您可以通过两种常见的方式在应用程序中放置更多的Cookie怪物:Grand Central Dispatch和NSOperationQueue。 第一种方式:大中央调度(GCD) 由于这是针对初学者的指南,因此我将开始介绍如何以最简单的方式使用GCD。 让我们将一个cookie怪物的cookie行命名为“调度队列”。 您可以通过以下方法获取公共调度队列: dispatch_get_main_queue :这是主线程的队列。 dispatch_get_global_queue :系统为每个应用程序提供四个并发调度队列,您可以使用此方法获取任何共享的并发队列。 它们非常适合于后台任务。 dispatch_get_current_queue :这将返回当前队列 您还可以通过dispatch_queue-create(queue_name, NULL).自己的串行调度队列dispatch_queue-create(queue_name, NULL). 现在您站在传送带(队列)上,开始将每个cookie(代码)包装到袋子(块)中。 您可以通过两种方式分发cookie:(1)将打包的cookie放在队列中,然后继续制作其他cookie和执行其他任务。 在这种情况下,您不必担心Cookie何时到达Cookie怪物,或该Cookie之前或之后有多少Cookie; (2)这是一个重要的cookie,您可以停止等待cookie到达cookie怪物。 在这种情况下,您尝试执行其他任何操作之前先确保已吃掉Cookie。 对于第一种情况,您是异步地将代码块分派到队列中。 在代码中看起来像这样: 第二种方式:NSOperationQueue GCD是同时分发Cookie的一种很好的简单方法。 但是,当您的cookie工厂变得越来越复杂时,您将需要对cookie和cookie行进行更多控制。 现在该探讨NSOperation和NSOperationQueue。 NSOperation是一个智能盒,您可以将其放入Cookie中。 其中一些可以包含多个cookie,一些可以处理自定义大小的cookie。 您可以指示小甜饼怪兽如何在每个包装盒中食用小甜饼,并以不同的优先级标记它们。 框中有一些按钮,可让您将Cookie标记为“已过期”(取消操作),还具有标签来显示Cookie是被食用还是已完成。 NSOperationQueue是用于处理智能盒子的升级传送带。 […]

中央中央调度(GCD)第一部分

众所周知,如果没有并发编程或多个CPU,愚蠢的计算机一次不能完成一项任务 点击此处获取示例应用 介绍 : 并发在编程语言中是一个巨大的话题,并且有点低级。 在本文中,我将讨论并行编程。 有很多用于并发的API.Apple发布了两个用于并发编程NSOperation和Dispatch Queue的低标签API。我将介绍Grand Canter Dispatch(GCD),并探讨我们为什么需要它以及如何使用Swift来实现它,并希望您能精通在这个API上..所以,让我们一起摇滚吧.. 那么为什么我们需要并发: 我们都知道计算机(单核)不能一次执行多任务。但是在计算中,多任务是必不可少的。因此,为了解决这个问题,发明了并发概念。并发是一次执行多任务的方式。 在高度上:考虑我们有一个应用程序,它一次有两个任务,一个是从网络下载数据,另一个是更新UI。两个任务都需要同时执行。如果下载(网络请求)需要一些时间,例如30此时用户界面将停止更新。并且应用程序将冻结甚至被压碎。从用户角度来看,它的作用各不相同。没有用户会再次使用此应用程序。 我们需要并发编程。 所以 在深入探讨并发之前,我们需要回顾一些定义,这将有助于我们进一步了解: 任务可以串行或同时执行两种方式 串行:任务可以一个接一个地执行。一个任务在其上一个任务完成时开始启动,例如FIFO(先入先出)。 我们可以举一个例子,例如电影院售票柜台。 如果有一个柜台,所有顾客都排队。 它是一个串行队列。当一位顾客购买票时,他将不在排队,下一位顾客将来取票。 它是一个串行队列。 并发: 并发只是一个概念,它可以同时运行多个任务,这可以在单核CPU或多核CPU中发生。在单核CPU中,它是通过时间分片来实现的。一个线程先执行上下文切换,然后再运行另一个线程线程或多核CPU通过并行执行多个线程。 并发是两种类型: 1,并发无并行 2并行并行 线程: 线程是进程的子单元,换句话说,线程是由操作系统调度程序独立调度的任务组。 Queue列: 队列是按先进先出(FIFO)的顺序管理对象的数据结构。在我们的示例电影票客户线上是队列。 为什么我们需要并发? 由于一些非常重要的原因,我们需要并发: 始终响应UI :在任何iOS应用程序首次启动时,默认情况下都会运行一个主队列。主队列可以更新用户界面。因此,我们需要使此队列仅用于UI和后台队列中的其他繁重任务。因此,此处进行并行编程需要解决这个问题。 利用iOS设备:如今,iOS设备是多核处理器,通过并发编程,我们可以并行使用多核处理器。 释放到主队列 大坎特派遣(GCD): 因此,我们已经为并行编程涵盖了足够的主题.Apple有两个用于并行编程的API.NSOperation和GCD。最常用的是GCD(Grand Canter Dispatch)。我们可以通过此API在iOS和MacOS上管理多线程。同步和异步任务队列。 GCD有调度队列,用于按FIFO顺序一个接一个地管理所有队列。GCD提供两种类型的队列,分别是串行队列和并发队列。这两个队列可以同步运行,也可以异步运行。我们将在一段时间后讨论。 串行队列: 串行队列可确保在任何给定时间仅运行一项任务。 GCD控制执行时间。 我们不知道任务何时开始并最终由调度队列管理。 在此图中,所有正在运行的任务都是按一个接一个的顺序执行的任务1比tast 2完成tn thn任务3启动等等… 并发队列: 并发队列一次运行多个任务。 所有任务都是按顺序添加的,但我们不知道什么时候全部完成或一次要执行多少任务都由系统管理。 如图所示,任务1开始并且这次没有任务在运行,但是任务1和任务2在同一时间启动,但是任务1在任务2之前完成了,所以并发队列我们不知道任务什么时候完成或如何完成我们将花费很多时间,我们只是知道任务将按照我们的订购方式运行。 它的依赖于调度到多个任务的队列将在不同的内核上运行或通过上下文切换发生。但是通常,如果内核可用而不是在内核上发生,则通常使用上下文切换。 GCD提供了三种主要的队列类型: […]

大中央调度-Swift 3

Grand Central Dispatch或GCD是一种在我们的iOS应用程序中处理多任务的方法。 该系统的工作方式是可以将许多任务发送到调度队列,而调度队列又将在多个线程上运行,并最终由系统进行管理。 当我们尝试在其中一个应用程序中更新UI时,常常会想到GCD。 这些更新发生在主线程上,但是我们可能需要执行其他任务,并且这些任务可以在并发线程或后台线程上运行。 要添加一些上下文,队列是可以在主线程或后台线程中同步或异步运行的代码块。 使用队列时,我们可以使用Apple提供给我们的全局队列,也可以创建自己的自定义队列。 应该注意的是,全局队列应该谨慎使用,因为我们不想滥用它们。 为了更好地理解其中一些概念的含义,让我们直接进入代码并创建队列。 let queue = DispatchQueue(标签:“ queue.1”) 在这里,我们创建了一个自定义队列,并为其分配了唯一的标签。 您所说的标签完全是任意的,但最好为其命名与您的应用相关。 我们可以在这些队列上调用不同的方法,例如异步与同步。 这些关键字将告诉我们的应用程序如何执行我们的代码。 这是我们的代码在后台线程上同步运行而在主线程上运行的代码的示例。 //后台线程 queue.sync { 对于i in 0 .. <10 { 打印(“🔷”,i) } } //主线程 对于20中的i。<30 { 打印(“⚪️”,我) } 如果运行此代码,我们将看到如下所示: //打印:🔷0🔷1🔷2🔷3🔷4 … ⚪️20⚪️21⚪️22⚪️23⚪️24 … 我们的程序将在主线程上运行的for循环处停止,因为它是同步的,因此它可以在队列中执行我们的代码块。 如果我们将队列更改为异步,我们的应用程序将可以在主线程上自由运行代码,并且还将同时在队列中执行代码块,因此我们得到如下信息: //打印: 🔷0⚪️20🔷1⚪️21🔷2⚪️22🔷3⚪️23🔷4⚪️24🔷 … 尽管主线程是应用程序中的最高优先级,但是我们也可以指定队列的重要性,并让我们的应用程序知道如何确定任务的优先级。 该规范称为服务质量 (QOS)。 QOS是一个枚举,我们可以按从最高优先级到最低优先级的顺序将以下值分配给列出的队列。 .userInteractive .userInitiated 。默认 。效用 […]

Swift S中的信号量之美

在这个故事中,我们将执行以下操作 : 了解什么是信号量 了解信号量如何工作 实施并解释2个示例 开始吧 信号量使我们能够控制多个线程对共享资源的访问。 为了简单起见,让我们考虑以下现实情况: 一位父亲和三个孩子坐在家里,然后掏出iPad … 孩子2 :我想玩iPad !!! 小孩1 :不!,我想先玩… 孩子3 :Ipad! iPad! iPad! *掌声* 父亲 :好的,孩子2,因为您首先问过,并且目前没有人使用iPad,请拿走它,但是一旦完成,请告诉我。 其他孩子,请耐心等待。 孩子2: (5分钟后)我做完父亲了。 父亲:孩子1,有iPad,请在完成后告诉我。 孩子1: (5分钟后)我做父亲了。 父亲:孩子3,有iPad,请在完成后告诉我。 孩子3: (5分钟后)我做完父亲了。 在上述方案中,父亲是信号量,iPad是共享资源,孩子是线程。 注意父亲如何确保一次只有一个孩子使用iPad。 如果将此与编程进行比较,则一次只能有一个线程访问共享资源。 另外,请注意使用顺序,首先询问的是谁(FIFO)。 提示 :共享资源可以表示变量,也可以表示工作,例如从url下载图像,从数据库读取等等。 如果父亲只是把iPad给孩子们怎么办? 飞机飞行到可能损坏的iPad😖的地步。 如果将其与编程进行比较,则多个线程会尝试同时访问同一资源,并且没有任何阻止。 这种行为可能导致争用情况,崩溃,并且显然,我们的代码将不是线程安全的。 线程安全:可以从多个线程安全地调用而不会引起任何问题的代码。

iOS并发介绍

通过 谢尔盖·沙巴林 ( Sergey Shabalin) 假设您有一个运行在主线程上的移动应用程序,负责执行操作UI的代码。 每当您在应用中打包一些耗时的代码(例如从Web上下载或在主线程上进行图像处理)时,这都会显着降低UI性能,甚至可能导致其完全死机。 iOS中的多线程 那么有没有办法改变应用程序的架构,使此类问题永远不会发生? 我相信并发在这里可以提供帮助,因为并发能够执行两个或多个独立任务,例如计算,从Web或驱动器上下载数据,图像处理等。 但是,这并不是免费的,随着并发性的引入,代码线程安全性可能会在执行中受到损害。 一旦允许任务同时执行,就为任务可以访问相同资源的问题做好准备,例如更改不同线程上的相同变量或访问已被其他任务阻止的资源。 这最终可能导致拆除在不同线程上使用的那些资源。 在iOS开发中,并发用于提高生产力和UI响应能力,这是由Thread,GCD(中央总调度)和Operation等多种工具提供的。 可以肯定地说,在Swift 3出现之前,强大的GCD框架正在使用C API,这为用户操作带来了很多隐患。 Swift 3改变了一切。 GCD获得了一种基于GCD逻辑的易于使用的新语法。 为了更好地了解如何使用并发,让我们找出哪些关键概念与GCD和Operation工具一起使用。 基本概念是队列 。 因此,从开发人员的角度谈论iOS并发时,很可能会提到队列。 队列中有闭合的队列,并根据指定的顺序,系统将它们一个接一个地拉,然后将它们部署在适当的线程上。 队列在构成并发模式的多个线程中遵循FIFO(先进先出)原则。 串行队列与并发队列 队列可以是: 串行或连续,当队列顶部的闭包被iOS拉出并运行直到结束时,再拉出另一个队列元素,依此类推。 并发或多线程,当系统在队列顶部拉一个闭包并在某个线程中启动其执行时。 如果系统有权访问更多资源,则它将从队列中选择下一个元素,并在第一个功能仍在工作时在另一个线程上启动它。 这样,系统可以提取许多功能。 同步方法与异步方法 创建队列后,有两种将作业放入队列的方法: 同步方法表示与当前队列有关的同步任务放置。 整个方法完成后, sync方法将控制权返回到当前队列,从而阻止了当前队列。 异步方法是与当前队列相关的异步任务布置。 与sync方法相反, Async在另一个队列上启动任务后立即将控件返回到当前队列,而无需等待其结束。 因此, 异步方法不会阻止当前队列上的任务执行。 可能会出现以下不同的队列 : 如果是异步执行方法, 则为 串行队列;如果是同步执行, 则为并发队列。 并发队列。 开发人员的任务完全取决于队列选择,并在同步方法的帮助下将任务(封闭)同步添加到队列中,或通过异步方法异步添加到队列中。 iOS从那里获取它。 全局调度队列 除了定制的用户队列之外,iOS还提供了一些五种现成的全局调度队列: 主队列。 负责所有UI操作: […]

Swift 3:使用Grand Central Dispatch实现多线程

自从Swift 3.0开源以来,它是Swift的第一个主要版本,自Swift 3.0到来以来,开发人员正在迅速赶上对核心语言和标准库的所有主要改进和改进。 大的欢迎变化之一是大中央调度 (GCD) 。 在性能,并发性,并行化和线程化方面,GCD是所有Apple平台上最常用的技术之一。 我们使用GCD解决的最常见的问题是在后台线程上运行任务的能力,以便不阻塞在主线程中运行的UI。 应用程序开发中的常见任务是从服务器下载图像,此任务可能需要x倍的时间才能完成,因此,如果您在主线程中运行此任务,则会阻止UI,并且用户将无法再操作该应用程序。 造成不愉快的用户体验,并可能使应用程序崩溃。 我们通过将任务分配给后台线程来解决GCD问题。 GCD通过将任务分配给主线程以外的其他线程或队列来利用CPU的多任务处理功能。 除了GCD,Apple还提供了NSOperationQueue框架来编写并发代码。 两者都旨在封装工作单元并分派它们以执行。 了解每个提供的好处将帮助您决定实施哪个。 在这篇文章中,我将主要关注GCD。 查看这个出色的博客,它解释了GCD和NSOperation的区别和好处。 在NSOperation和中央中央调度之间进行选择– Cocoacasts 自iOS 2起NSOperation和NSOperationQueue自iOS 2可用以来,Grand Central Dispatch(简称GCD)是…… cocoacasts.com Swift 3对GCD的更改使开发人员更容易,尤其是像我这样的新开发人员更容易回忆起代码并在项目中应用。 在Swift 3发布GCD语法之前,编码风格非常接近底层C,并且与Swift中的任何其他编码风格都明显不同。 新的GCD API主要围绕DispatchQueue旋转。 此类允许创建和修改队列, 同步或异步调度代码等等。 AD ispatchQueue可以是serial ,因此可以一次执行一个工作项,也可以是并发的 ,以使工作项按顺序出队,但可以一次全部运行并且可以按任何顺序完成。 串行队列和并发队列均以先进先出(FIFO)顺序处理工作项。 同步本质上是指“有序”。基本上,当您执行同步操作时,以后出现的所有内容都必须等待操作完成才能开始。 异步或多或少意味着“不按顺序进行”。当您异步执行某项操作时,以下代码可以立即运行,并且异步操作将……运行。 它可能与其他代码在另一个线程上并行运行。 可能只是在同一线程上安排了其他时间。 GCD分派使在后台线程上执行异步操作异常容易。 让我们从我当前正在使用的电影应用程序中查看下面的代码块。 首先,我对OMDB(电影数据库)服务器进行了API调用,如果请求成功,我将解析JSON并更新DispatchQueue.main.async {…}块内的UI。 DispatchQueue块内的任何代码,例如上传电影海报图像,都将在单独的线程上运行,并在完成后更新UI。 在运行此任务时,用户仍然可以不受阻碍地操作应用程序。

iOS iOS中的多线程入门

随着我们所有移动设备中多核处理芯片的出现,它带来了在应用程序中同时执行多个任务的可能性。 在iOS中, 为了使应用程序的UI保持响应状态,所有繁重的任务都添加到了新线程中,例如,网络调用。 这些线程通常在后台运行,并在必要时发送回叫以更新UI。 苹果文档中已完美说明了多线程需求,它说: OS X或iOS中的每个进程(应用程序)都由一个或多个线程组成,每个线程代表通过应用程序代码执行的单个路径。 每个应用程序都从一个线程开始,该线程运行该应用程序的主要功能。 应用程序可以产生其他线程,每个线程都执行特定功能的代码。 为了方便和安全地管理这些额外的线程,我们需要一个框架,例如dispatch multi 实现多线程的方法: –大中央派遣 – NSThread – NSOperationQueue 本博客假定您对这些类型有基本的了解。 比较这些方法时: Code/Structural Origins: GCD是基于C的底层API。 NSOperation和NSOperationQueue是Objective-C类(GCD上的包装器)。 NSThread是一个NSObject(使用pthreads)。 Complexity comparison: 对于GCD实施非常轻巧 NSOperationQueue非常复杂且重量级 NSThread只是pthread的包装器,因此也使其轻巧。 NSOperation advantages over GCD and NSThread: 您可以: 因此,在两个NSOperation之间建立依赖关系,使开发人员可以按特定顺序执行任务。 一旦任务开始执行,就暂停,取消,恢复NSOperation,因此可以控制该操作的生命周期。 监视操作的状态,例如:准备,执行或完成。 指定可以同时运行的最大排队操作数。 显然,NSOperationQueue为您提供了对操作的更多控制。 一旦确定了要使用的方法,就需要确定其顺序和优先级。 Order of Operation: 队列可以有两种类型:串行队列或并发队列,分别分别同步和异步运行任务 Priority of operations: 优先级定义为称为QoS的服务质量,分为以下四种类型: 现在,我们通过预测几个示例的输出来尝试了解这些操作。 在尝试回答下面的代码输出之前,让我们看一下dispatch_async和dispatch_sync的文档: Dispatch_async: 🤞🏼声明void dispatch_async(dispatch_queue_t队列,dispatch_block_t块)👥讨论此函数是用于将块提交到调度队列的基本机制。 […]

运营和中央调度的面试问题(第二部分)

iOS面试问题,gcd面试问题,多线程ios面试问题,iOS 在本文中,我将介绍一些与Dispatch相关的问题,但是解决方案以目标C语言给出,并且可以在Swift上移植。 为这些问题在目标C中提供解决方案的原因是我在Citrix等公司接受采访的一位朋友,他们之所以要求在目标C中编写解决方案,是因为开放是面向同时了解obj C和Swift的开发人员的。 希望它也能帮助其他开发人员,让我们开始吧。 Q1。 dispatch_once和dispatch_once_t的用途是什么,用示例写下代码? 解决方案 : 单身人士 Q2。 dispatch_after的用途是什么,用示例写下代码? 解决方案 :如果您需要在特定的时间点运行某些内容,那么dispatch_after可能是正确的选择。 一定也要检查NSTimer。 Q3。 什么是目标队列,用示例写下代码? 解决方案 : 惊喜:您已经在使用它们! 您创建的任何队列都必须具有目标队列。 默认情况下,它设置为DISPATCH_QUEUE_PRIORITY_DEFAULT全局并发队列。 Q4。 下面的代码有什么问题,如何解决? 解决方案 : dispatch_set_target_queue使从firstQueue或secondQueue执行的每个块都表现得“好像”已使用dispatch_async提交给并发队列。 成为目标队列不会影响dispatch_barrier_ *函数的语义。 屏障保证在屏障块运行时队列中没有其他任何执行。 Q5。 编写用于创建所有类型的队列的代码,还让我们知道优先级吗? 解决方案 : Q6。 编写一个资源,多个读取器和一个写入器的代码(基本上是用于多线程读取和单线程写入的读取器写入器)? 解决方案 :同步/异步模式的一种优化是读写器模式,在该模式下,允许并发读取,但不允许并发写入。 因此,您将使用并发队列,dispatch_barrier_async进行写操作(实现写操作的类似串行行为),但是使用dispatch_sync进行读操作(就其他读取操作而言,享受并发性能)。 Q7。 编写死锁条件代码? 解: Q8。 什么是dispatch_apply ? 为用例编写代码? 解决方案: dispatch_apply —迭代执行性能的改进,请查看下面的示例以更加清楚。 Q9。 编写DispatchGroup用例的代码? 解: Q10。 编写DispatchGroup用例的代码? 解: […]