Tag: grand central dispatch

iOS中的同步队列与异步队列

我首先遇到的问题是,在处理包含从数据库下载的文本和图像的UITableView时,在主异步队列中声明下载任务的目的是什么。 但是,等等,什么是主队列,什么是同步或异步内容? 为什么我们需要它们? 首先,在您的iOS APP中有许多工作正在执行。 当然,还有一些重要的任务,就像还有一些不太重要/紧急的任务一样。 队列:串行和并发。 串行队列一次处理一个任务。 并发队列可同时处理多任务。 异步和同步是通信实践。 一般来说,同步阻止等待处理的任务,直到当前任务完成为止;另一方面,异步允许进行多线程任务。 (请参见此处的参考:http://www.cs.unc.edu/~dewan/242/s06/notes/ipc/node9.html) 主队列和全局队列 。 顾名思义,主队列具有被处理的优先级。 iOS APP中的线程就像高级方法。 主线程就像主分配器。 (详细的很棒的解释:https://stackoverflow.com/questions/19179358/concurrent-vs-serial-queues-in-gcd) 根据经验,与您的APP UI演示有关的任务是这些重要任务,必须优先处理。 将复杂或耗时的计算任务放在后台线程中。 因此,在主队列中声明下载(UI)任务。 像这样: //这里有一个tableView,其单元格images(houseImage)依赖于从数据库下载的图像:cell.houseImage.image = UIImage(data:data!)//由于它是我们的主要UI组件; 在主线程中声明此下载任务:DispatchQueue.main.async {cell.houseImage.image = UIImage(data:data!)} “` 现在,用户将很高兴。 我希望你们也对此感到满意!

快速浏览Grand Central Dispatch和Swift 3

多线程和并发对于现代应用程序是必不可少的……但是,Grand Central Dispatch是用于管理并发操作的系统级库,它具有iOS SDK中较为麻烦且不友好的API之一。 不再。 Swift 3带来了对Grand Central Dispatch语法和用法的许多改进。 这是一些新功能的快速浏览。 dispatch_async 以前,我们将选择调度方法(同步与异步),然后选择要向其调度任务的队列。 更新后的GCD会颠倒顺序-我们首先选择队列,然后应用调度方法。 最常见的GCD模式之一是在全局后台队列上执行工作,并在工作完成后立即更新主队列上的UI。 新API的外观如下: 队列属性 您会注意到,队列现在在init上具有属性。 这是一个Swift OptionSet,可以包括队列选项,例如串行与并发,内存和活动管理选项以及服务质量(.default,.userInteractive,.userInitiated,.utility和.background)。 服务质量取代了iOS8中不推荐使用的旧优先级属性。 如果您习惯了优先级队列,请按照以下方法将它们映射到QOS案例: * DISPATCH_QUEUE_PRIORITY_HIGH:.userInitiated * DISPATCH_QUEUE_PRIORITY_DEFAULT:.default * DISPATCH_QUEUE_PRIORITY_LOW:.utility * DISPATCH_QUEUE_PRIORITY_BACKGROUND:.background 内存和活动管理选项是今年的Apple OS版本(OSX 10.12,iOS 10.0,tvOS 10.0,watchOS 3.0)的新增功能。 这些功能包括使用.initiallyInactive在非活动状态下启动队列或使用.autoreleaseInherit,.autoreleaseNever和.autoreleaseWorkItem为队列设置自定义自动释放设置的功能。 工作项目 队列不是GCD获得Swift OptionSet的唯一部分。 工作项目也有更新的Swift语法: 现在,工作项可以在初始化时声明质量或服务和/或标志。 这两个都是可选的,并且会影响工作项的执行。 这些标志是一个选项集,其中包括以下选项:barrier,detached,assignCurrentContext,noQoS,InheritanceQoS,forceforceQoS。 一次派遣 dispatch_once对于初始化代码和仅执行一次的其他功能非常有用。 在Swift 3中,不建议使用dispatch_once,而应将其替换为全局或静态变量和常量。 dispatch_time_t dispatch_time_t是将指定时间转换为可以提供给队列的UInt64的函数。 更新的GCD为此引入了更友好的语法(告别NSEC_PER_SEC)。 这是一个使用after之后的示例: .seconds是名为DispatchTimeInterval的新枚举的一部分。 这些案例具有一个代表计数的关联值。 目前支持: * […]

Swift并行编程—第1/4部分

并发,并行和调度队列 每当我们听到并行编程时,就会想到两个令人困惑的术语:并发和并行。 首先让我们看看现实生活中的角色: 并发性:我们的日常工作涉及多任务处理。 很多时候,我们执行多任务处理,但最终会同时完成一个任务,但是理想情况下,这就是上下文切换。 它也有一些限制。 假设我们每天有100项工作,但不能将其增加到1000项。 并行性:如果我们可以得到更多的物理东西,那么可以同时完成两个或更多的工作。 如果我有4臂,那么这篇文章可以在一半的时间内完成。 让我们来看看计算机世界中的两个术语: 并发: 并发意味着应用程序同时(并发)在一项以上的任务上取得进展。 如果计算机只有一个CPU,则该应用程序可能无法完全同时执行一项以上的任务,但是一次要在应用程序内部处理一项以上的任务。 在开始下一项任务之前,它并没有完全完成一项任务。 当我们谈论至少两个或更多任务时,并发本质上是适用的。 当一个应用程序几乎可以同时执行两个任务时,我们称其为并发应用程序。 尽管这里的任务看起来像是同时运行的,但实际上它们可能并非如此。 它们利用了操作系统的CPU时间分片功能,其中每个任务运行其任务的一部分,然后进入等待状态。 当第一个任务处于等待状态时,CPU被分配第二个任务以完成其部分任务。 操作系统根据任务的优先级工作,因此分配CPU和其他计算资源,例如内存; 依次处理所有任务,并给他们完成任务的机会。 对于最终用户,似乎所有任务都是并行运行的。 并发复杂度 假设有5个朋友搬进了房子,每个人都有一张床。 哪种更复杂的方式来构造它? 5人同时组装一张床或 每个人组装自己的床 想一想如何为几个朋友编写有关如何将床组装在一起的说明,而无需彼此扶持或等待工具。 他们需要在正确的时间协调动作,以将床的各个部分组装成成品床。 这些指令真的很复杂,很难编写,也可能很难阅读。 每个人都自己建造床时,说明非常简单,无需等待其他人完成操作或使用工具即可。 罗伯·派克 ( Rob Pike)有一个关于 并发不是并行的演讲。 平行性 并行不需要两个任务存在。 通过为每个任务或子任务分配一个内核,它可以使用CPU的多核基础结构同时运行部分任务或多个任务。 并行性本质上要求具有多个处理单元的硬件。 在单核CPU中,您可能会获得并发性,但不能获得并行性。 并发是独立执行的进程的组成,而并行性是计算的同时执行。 并行性是指应用程序将其任务分解为较小的子任务,这些子任务可以并行处理,例如在多个CPU上同时进行。 并发是一次处理很多事情,更多的是关注结构。 并行性是一次执行很多事情,其重点是执行。 一个应用程序可以是并发的,但不能是并行的,这意味着它可以同时处理一个以上的任务,但是两个任务不能同时执行。 一个应用程序可以是并行的,但不能是并行的,这意味着它可以同时处理多核CPU中一个任务的多个子任务。 应用程序既不能是并行的,也不能是并发的,这意味着它一次顺序地处理所有任务。 一个应用程序可以是并行的,也可以是并发的,这意味着它可以同时在多核CPU中同时处理多个任务。 自从出现以来,CPU技术的最大改进之一就是能够包含多个内核,因此可以运行多个线程,这意味着在任何给定时刻可以执行多个任务。 在iOS中,有两种实现并发的方法:Grand Central Dispatch和OperationQueue。 这两个主题都很广泛,因此我将本文分为四个部分 : […]

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😖的地步。 如果将其与编程进行比较,则多个线程会尝试同时访问同一资源,并且没有任何阻止。 这种行为可能导致争用情况,崩溃,并且显然,我们的代码将不是线程安全的。 线程安全:可以从多个线程安全地调用而不会引起任何问题的代码。

大中央调度(GCD)第二部分

在第一部分中,我们介绍了串行和并发队列以及示例。在这一部分中,我们将详细介绍有关具有参数更改的并发队列的苹果,并学习如何创建全局队列,非活动队列,时间延迟,死锁。 让我们从我们离开的地方开始。 InactiveQueue: 在attribute参数中有另一个值initialInactive。因此,我们可以首先使非活动队列成为队列,当需要活动时,我们可以使它处于活动状态。 让我们将属性值并发更改为initialInactive,如下所示: let newQueue = DispatchQueue(标签:“ com.concurrent.ekram”,qos:DispatchQoS.background,属性:.initiallyInactive) 并在并发函数的外部块中创建DispatchQueue的类属性: var inactiveQueue:DispatchQueue! 现在在这样的函数中使用newQueue初始化不活动队列: inactiveQueue = newQueue 现在,newQueue处于非活动状态,并且viewDidAppear不知道队列,因此需要在viewDidAppear中手动激活,如下所示: 如果让队列= inactiveQueue { queue.activate() } 现在,代码将以串行方式运行并执行队列。请参见屏幕和控制台: 最初不活动时如何使用并发: 属性参数很简单,请同时使用.initiallyInactive和的数组。 并发比队列最初也将处于非活动状态并发。 let newQueue = DispatchQueue(标签:“ com.concurrent.ekram”,qos:DispatchQoS.background,属性:[。initiallyInactive,.concurrent]) 现在的结果是: 因此,当我们使用active()方法在viewDidApper上同时运行时,newQueue最初也处于非活动状态并且是并发的。 创建全局队列: 我们已经知道如何使用property创建自定义队列。 实际上,我们不需要创建全局队列,因为GCD工程师已经为我们创建了全局队列。因此,我们可以像这样创建.. 让globalQueue = DispatchQueue.global() 我们可以添加到全局队列方法 globalQueue.async { 对于i in 0 .. <10 { 打印(“ Custom Green Love:Custom”,i) } } […]

大中央派遣-如何终端! (快速3)

嗯,多线程,并发等等。 这些都是在Flatiron学校的话题,我们被告知“这确实很重要”,现在我开始寻找工作,阅读工作说明并进行技术面试,现在我意识到Flatiron并不是在撒谎。 因此,在这里,我们只关注一件事: 中央中央调度(GCD) 。 Grand Central Dispatch(以前称为libdispatch的框架)是Apple的框架,用于将并发(管理同时发生的多件事)合并到您的应用程序中。 基本上,GCD会为我们管理队列(为我们完成所有任务调度!),因此我们不必考虑如何合并线程或在哪里“锁定”代码行。 GCD允许我们(开发人员)考虑将代码编写为单个线程或进程,因此,我们只需要考虑在哪里分解我们的部分代码以在另一个线程上运行。 Apple文档指出,“ GCD提供并管理FIFO(先进先出)队列,您的应用程序可以以块对象的形式向其提交任务。 提交给调度队列的工作在系统完全管理的线程池上执行。 无法保证执行任务的线程。” 简而言之,GCD是我们的小帮手,因为它: 因为它在后台运行长时间运行的任务,所以有助于提高我们的应用性能。 通过避免在新线程上设置锁和分离代码的需要,使开发人员更轻松(如果操作不正确,可能会导致并发错误) 可以提高代码性能,例如单例。 因此,让我们退后一步,回顾一些在开始讨论GCD之前需要理解的词汇和概念: 任务=需要完成的一项工作(即API调用)。 线程=操作系统提供的进程,它允许多个指令集(又称代码行)在单个应用程序中同时运行。 进程=代码的可执行部分,可能在多个线程中。 太酷了,既然我们已经把这些术语简化了,让我们来谈谈任务的执行方式。 串行调度队列与并发调度队列 如果一项任务一次执行一次,则称它是串行执行的。 如果可以同时执行多个任务,则称它们是同时执行的。 Grand Central Dispatch提供了调度队列(以“队列”为一行),使您可以在所谓的并发调度队列上并发运行代码块。 使用并发调度队列,我们​​有多个线程可用于同时处理多个代码块。 这种队列不同于串行调度队列 , 串行调度队列一次只在一个线程上添加一件工作。 同步与异步执行 函数可以是同步的也可以是异步的。 同步功能仅在上一个任务完成后返回 。 我喜欢将其视为“同步”(有趣的事实:NSYNC是我一直以来最喜欢的男孩乐队)。 异步意味着它可以立即运行,而无需等待上一个任务完成就可以开始。 因此,它不是同步的(我喜欢将异步看作是我的NSYNC的后街男孩)。 大中央调度:我们如何使用它? 如前所述,GCD为我们提供了调度队列,用于管理代码块。 这些分派队列负责处理我们提供给GCD的任务,并按FIFO ( 先进先出 )顺序进行处理(第一个任务排在队列的首位,依此类推)。 您还记得在串行调度队列中 ,一次只执行一个代码块。 在GCD中,这些块的执行时间在GCD的控制之下。 换句话说,我不知道代码的第1、2和3块要花多长时间,但是我知道两件事:1)每个块一次要运行一个,2)他们要运行一次以添加它们的顺序运行。 对于并发调度队列,可以同时执行多个代码块。 GCD的工作是决定何时启动每个块。 由于这些是同时运行的多个代码块,并且将重复执行这些代码块,因此GCD 决定何时这些块之一应在其他内核上运行 (一个内核是计算机的处理器之一。我的Macbook […]

Swift并行编程—第2/4部分

目标队列,调度组,屏障,工作项,信号量和调度源 本文是Swift并行编程的第2部分。 与第1部分一样,我们研究了Dispatch Queue和系统提供的队列。 在本文中,我将重点介绍另一种定义任务和GCD提供的强大API的方法。 如果要查看系列的所有部分: 并发和GCD — Swift并行编程— 1/4 GCD —使用Swift进行并行编程—第2/4部分 议程: 目标队列 调度组 DispatchWorkItem 派遣壁垒 DispatchSemaphore 派遣源 1.目标队列 定制调度队列不执行任何工作,它只是将工作传递给目标队列。 默认情况下,自定义调度队列的目标队列是默认优先级的全局队列。 从Swift 3开始,一旦调度队列被激活,就无法再对其进行更改。 可以通过setTarget(queue:)函数设置自定义队列的目标队列。 在激活的队列上设置目标将进行编译,但随后会在运行时引发错误。 幸运的是,DispatchQueue初始化程序接受其他参数。 如果出于某种原因仍然需要将目标设置在已创建的队列上,则可以使用iOS 10以来可用的initiallyInactive属性来实现。 DispatchQueue(标签:“队列”,属性:.initiallyInactive) 这将允许您修改它,直到激活它。 DispatchQueue类的activate()方法将使任务执行。 由于队列尚未被标记为并发队列,因此它们将以串行顺序运行。 为了使队列并发,我们需要指定: DispatchQueue(标签:“队列”,属性:[。initiallyInactive,.concurrent]) 您可以将任何其他调度队列(甚至是另一个自定义队列)传递给目标队列,只要您从未创建周期即可。 通过简单地将自定义队列的目标队列设置为其他全局队列,可以使用该功能设置自定义队列的优先级。 只有全局并发队列和主队列才能执行块。 所有其他队列必须(最终)以这些特殊队列之一为目标。 您可能已经在使用的Dispatch API或框架中注意到了目标队列。 我在RxSwift库中发现了目标队列的使用。 使用此实现,由于任务正在异步执行,因此很难在完成时获得通知。 这是DispatchGroup图片: DispatchGroup允许工作的聚合同步。 它可以用于提交多个不同的工作项或块,并跟踪它们何时全部完成,即使它们可能在不同的队列中运行。 唯一必要的事情是在调度组上均衡地调用enter()和leave() ,以使其同步我们的任务。 调用enter()以手动通知组任务已开始,并leave以通知工作已完成。 您也可以调用group.wait() ,它会阻塞当前线程,直到该组的任务完成为止。有两种方法来调用完成块: 使用wait()然后在主队列上执行完成块 呼叫组notify() wait(timeout:) 这将阻止当前线程,但是在指定的超时后,无论如何仍将继续。 […]

iOS派遣组

通常,在iOS应用程序中,我们会尝试为应用程序提供功能,使其能够同步​​由于网络故障而无法发送的某些请求。 一个快速的实现是在UserDefaults中缓存一些简单的String,或者缓存其中的数组。 在应用程序变为活动状态期间,您可以尝试运行DispatchGroup() 这只是我的一个简单发现,即快速,轻松且易读 想象一下,如果您有一系列要发送给请求的帖子,并且只想在所有请求都完成后才希望获得回调,那么您可以通知用户脱机帖子已经发送,并且可以清理缓存。 令group = DispatchGroup()for in in 0 .. <n { group.enter() //这是一个示例伪代码 //不是完全运行的代码 MyNetworkClass.request(){在 group.leave() } } group.notify(队列:.main){ 打印(“所有请求都已完成”) } 因此,使用此示例代码片段,您可以将其抽象为实用程序功能,以处理应用程序中缓存项的发送,并在所有请求完成后进行清理

如何防止temporaryContext与migratePersistentStore同时运行

我有一个代码部分,我调用migratePersistentStore ,我想阻止任何temporaryContext在同一时间做任何事情,如何? 我的想法是基于semaphore和dispatch_group 。 代码A: dispatch_group_wait(dgLoadMain, DISPATCH_TIME_FOREVER) dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER) mainMOC!.performBlockAndWait({ mainMOC!.persistentStoreCoordinator!.migratePersistentStore(/* … */) }) dispatch_semaphore_signal(semaLoadMain) 代码B: dispatch_group_enter(dgLoadMain) dispatch_semaphore_wait(semaLoadMain, DISPATCH_TIME_FOREVER) dispatch_semaphore_signal(semaLoadMain) let context = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) context.parentContext = mainMOC var context: NSManagedObjectContext context.performBlockAndWait({ // .. some code I do not want to run when migrating persistent store context.save(nil) }) mainMOC.performBlockAndWait({ mainMOC.save(nil) }) dispatch_group_leave(dgLoadMain) 你怎么看待这件事? 任何bette解决scheme? 在这种情况下可以使用dispatch_barrier_async吗?

如何从Helper类返回值到视图控制器?

我有一个viewcontroller,在它的viewDidLoad中调用一个HelperClass类的方法,像这样: – (void)viewDidLoad{ [super viewDidLoad]; self.usersArray = [SantiappsHelper fetchUsers]; } 该类的方法如下所示: +(NSArray *)fetchUsers{ NSString *urlString = [NSString stringWithFormat:@"http://www.myserver.com/myApp/getusers.php"]; NSURL *url = [NSURL URLWithString:urlString]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10]; [request setHTTPMethod: @"GET"]; __block NSArray *usersArray = [[NSArray alloc] init]; dispatch_async(dispatch_get_main_queue(), ^{ // Peform the request NSURLResponse *response; NSError *error = nil; NSData *receivedData = […]