浅谈iOS多线程

首先,先看看进程和线程的概念。

图1.1

这一块不难理解,重点点下他们的几个重要区别

1,地址空间和资源:进程可以申请和拥有系统资源,线程不行。资源进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

2,通信:进程间需要用到IPC(这个可以谁总结开个课),线程可以直接读写进程的数据段来通信(需要涉及锁,下面会简单讲到)。

3,调度和切换:线程快,进程慢。

好了,切回主题,iOS多线程技术,一般有三个,NSThreadNSOperation/NSOperationQueueGCD(Grand Central Dispatch,好,首先先抛出一些概念。

NSThread

  • 使用NSThread对象建立一个线程非常方便。
  • 但是!要使用NSThread管理多个线程非常困难,不推荐使用。
  • 技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术。

NSOperation/NSOperationQueue

  • 是使用GCD实现的一套Objective-C的API。
  • 是面向对象的线程技术。
  • 提供了一些在GCD中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系。
  • 苹果官方现在建议大家使用该多线程技术,但现在仍然很多人使用GCD技术,因为GCD使用较为方便。

GCD —— Grand Central Dispatch

  • Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法,称作大中心调度。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。
  • 是基于C语言的底层API。
  • 用Block定义任务,使用起来非常灵活便捷。
  • 提供了更多的控制能力以及操作队列中所不能使用的底层函数。

以上就是对于这三种技术的简单介绍,接着再来介绍下几个基本的概念,

队列:队列是先进先出(FIFO)结构的,在iOS中,队列主要的任务是负责线程的创建、回收工作,不论什么队列和什么任务都不需要程序员参与,减轻了程序员的工作。有GCD队列和自定义队列。根据这些,我们实际上可以操作四种队列,全局队列,主队列,串行队列,并行队列。

任务:分为同步任务和异步任务。同步任务:必须按照顺序执行的任务,异步任务:执行顺序不一定,哪个先抢占到资源哪个先执行(我试过将多个异步任务并发执行,系统会将这些任务分配给若干个线程,然后由线程调度执行,分配到同一线程的任务还是按顺序执行的)。

于是乎,将这些队列和任务组合,就会出现8种组合,赶紧投票吧,分享会上用代码来详细讲解下这8种组合的效果。

下面简单介绍下以上三个技术在代码中的使用:

NSThread 使用它经常是用来查看当前线程:[NSThread currentThread](用来判断是否在主线程执行也很方便),因为其他的确实不好用,也不推荐用。

NSOperation/NSOperationQueue 虽说是苹果基于GCD实现的面相对象的线程技术,但是感觉用起来没有GCD方便,下面简单介绍下它的几个用法

NSOperation 对应任务 有以下三种用法

1  NSInvocationOperation

2  NSBlockOperation

3  自定义NSOperation 子类

1 和 2 我给出初始化方法 大家就一眼能知道区别和用法了。

NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];// 调用start方法执行操作op操作
[op start];
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"task0---%@", [NSThread currentThread]);
}];
[op start];

恩 其实就是调用的是block还是方法的区别了。注意 start后是指在当前线程同步执行任务。

自定义子类也说下

主要操作就是继承NSOperation,然后在.m文件中实现- (void)mian方法,然后运行start的时候就会运行main方法里的代码。

另外 任务提供执行完成的回调

op.completeBlock可以监听一个操作执行完毕的时刻,这个block里面可以添加一些我们需要执行的操作,这个block里面的操作仍然是在子线程执行,但不一定和被监听的操作在同一个线程

接着讲下NSOperationQueue

NSOperationQueue 对应队列 且是并行队列

先解决个疑惑,如何使用串行队列?NSOperationQueue提供了一个设置最大并发数的方法setMaxConcurrentOperationCount: 只要将最大并发数设置为1,就是串行队列了。

首先 NSOperationQueue 可以获取到主队列 或者自己创建。

NSOperationQueue 提供 addOperationaddOperationWithBlock方法 名字取得很好,一眼就可以看出用法了,前者用来添加任务,后者用block的方式来添加任务。

同时提供cancal单个任务和cancelAllOperations所有任务的方式,不能cancel正在执行的任务。

同时提供获取挂起状态和设置挂起状态的方法。

isSuspended : 判断是否挂起

setSuspended: YES表示挂起,NO表示恢复

同样 不能对正在执行的任务设置。

任务间的执行先后,可以设置依赖来排序。

[op2 addDependency:op1];

Op1执行完成后才执行op2.

其实简单的操作用NSOperation比起GCD来要美观一下,个人感觉。

最后讲重点GCD 我觉得它之所以强大是因为它提供了不止前面这些功能还提供了一些常用的额外功能,下面我来一一讲解。

几个简单的和前面功能类似的

dispatch_get_global_queue 全局队列 并行队列
dispatch_get_main_queue 主队列 主线程中的唯一队列
dispatch_queue_create 自定义队列 DISPATCH_QUEUE_SERIALDISPATCH_QUEUE_CONCURRENT 并行
dispatch_sync 同步线程
dispatch_async 异步线程
 
这些用法和前面类似 到时8个组合用GCD简单演示下,相当于两个一起理解了。
 
之所以说GCD比NSOperation强大,就是他不仅能实现NSOperation能实现的,还有很多很好用的方法,下面一一讲解
 
dispatch_once 一次性代码 使用dispatch_once保证代码只被执行一次 使用场景:单例对象的初始化 这个大家接触的很多了 不多讲了
 
dispatch_group_t 队列组 使用这个可以很好的控制任务调度
 
我们经常有需求 需要在一个页面请求多个接口 当多个接口都完成后执行刷新UI的操作 这个时候我们的操作一般都是多个异步返回的时候各自判断 其实用dispatch_group_t 可以很好的解决这个问题
 
思路如下
dispatch_group_t group =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 异步取数据A
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 异步取数据B
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 等前面的异步操作都执行完毕后,回到主线程刷新UI
});
 
dispatch_group_notify是队列组中所有任务都完成后会发送的通知。
 
思考下:我们的业务场景经常能用到这个思路,大家有没例子的?
 

dispatch_after 这个其实也挺经常用到的 延迟执行方法 网上说只是延迟提交,并不是延迟立刻执行 会有些许的时间差。

 

dispatch_barrier_async 确保提交的闭包是指定队列中在特定时段唯一在执行的一个  这个可以当锁用。

//创建队列
self.isolationQueue = dispatch_queue_create([label UTF8String], DISPATCH_QUEUE_CONCURRENT);
//改变setter
- (void)setCount:(NSUInteger)count forKey:(NSString *)key
{
     key = [key copy];
     //确保所有barrier都是async异步的
     dispatch_barrier_async(self.isolationQueue, ^(){
          if (count == 0) {
               [self.counts removeObjectForKey:key];
          } else {
               self.counts[key] = @(count);
          }
     });
}
这是网上找的代码 实际上synchronized可以更好的完成这个锁操作,这是后话啦,有空再分析这个。实际上他的用法也比较多,到时搞个demo分享下。
 

dispatch_apply 可进行快速迭代

用来替换对前一次计算没有依赖的for循环会优化很多,例如

for (int i = 0; i < 999 ; i++) {
            dispatch_async(concurrentQueue, ^{
                NSLog(@"wrong %d",i);
                //do something hard
            });
        }
改用dispatch_apply 来处理 
 dispatch_apply(999, concurrentQueue, ^(size_t i){
            NSLog(@"correct %zu",i);
            //do something hard
        });
 
Dispatch IO 文件操作
用到的方式是多个线程去读取不同的数据块,然后再合并。
 
Dispatch source 这个也是程序优化的一道利器,且支持多种场景,对于程序优化很有帮助,这块可以大力研究下,用Dispatch source来取代一些回调函数可以有效的提高程序执行的效率,codereview下我们的代码,应该有能够用上这块的(到时奉上)。
 

Dispatch Semaphore这个类似于操作系统中的信号量,可以用来解决死锁的问题。这个其实是个很有趣的领域,


 
dispatch_semaphore_wait等待信号量 需要dispatch_semaphore_signal执行后才能跳过。配合使用可以解决很多复杂的线程问题。
 
发挥下想象力:通过这个信号量,是不是用很好的方式解决我们请求等待同步的问题?
 
最后稍微讲下
建议使用synchronized就可解决大部分的问题了 给出ElearningConfig中的代码示例
 
 

 
 
实际上就是这段被{}包起来的代码只会被一个线程调用,而锁就是self对象。意思就是,执行代码块的时候会对self上锁,当下一个线程需要对代码块调用时,需要等待上一个程序解锁self才可以
 
好啦,更多精彩内容,我们分享会见!
 
 
 
 
 
 

浅谈iOS多线程的更多相关文章

  1. 浅谈iOS视频开发

     浅谈iOS视频开发 这段时间对视频开发进行了一些了解,在这里和大家分享一下我自己觉得学习步骤和资料,希望对那些对视频感兴趣的朋友有些帮助. 一.iOS系统自带播放器 要了解iOS视频开发,首先我们从 ...

  2. 浅谈iOS中的userAgent

    浅谈iOS中的userAgent   User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产 ...

  3. 浅谈iOS需要掌握的技术点

    鉴于很多人的简历中的技术点体现(很多朋友问我iOS需要知道注意哪些)! 技术点: 1.热更新 (及时解决线上问题) 2.runtime(json解析.数据越界.扩大button点击事件.拦截系统方法) ...

  4. 浅谈iOS中MVVM的架构设计与团队协作

    说到架构设计和团队协作,这个对App的开发还是比较重要的.即使作为一个专业的搬砖者,前提是你这砖搬完放在哪?不只是Code有框架,其他的东西都是有框架的,比如桥梁等等神马的~在这儿就不往外扯了.一个好 ...

  5. IOS中 浅谈iOS中MVVM的架构设计与团队协作

    今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  6. 浅谈 iOS 与 H5 的交互- JavaScriptCore 框架

    前言 小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCo ...

  7. 浅谈iOS中MVVM的架构设计与团队协作【转载】

    今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...

  8. 浅谈iOS开发的协议(protocol)和代理(delegate)

    协议和代理对于一个新手来说确实不讨好理解,也有很多的iOS开发的老手对此是懂非懂的.网上的很多博文只是讲了怎么使用,并没有说的很明白.下面我谈一下我的理解. 1.你要先搞明白,协议和代理为什么会出现, ...

  9. 浅谈iOS程序员的成长和进阶

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

随机推荐

  1. DHCP:动态主机配置协议

    DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)是一个局域网的网络协议,使用UDP协议工作, 主要有两个用途:给内部网络或网络服务供应商自动分配IP ...

  2. BZOJ 1189 紧急疏散(二分+最大流)

    求出所有人撤离的最短时间.由于每扇门只能通过一次,所以不能简单用bfs来搞. 显然答案是有单调性的,考虑二分,问题变成了判断时间x所有人能不能撤离. 考虑最大流.对于每扇门,每个时间通过的人数最多为1 ...

  3. Now or later UVALive - 3211(2-SAT 最小值最大化)

    emmm...去吃早饭了... rujia讲的很好.. 最小值最大化问题,,,二分枚举答案   设x1.x2为同一个集合中的元素,y1.y2为另一个集合中的元素,如果x1与y1之差小于mid,那么如果 ...

  4. [JSOI2009]游戏 二分图博弈

    题面 题面 题解 二分图博弈的模板题,只要会二分图博弈就可以做了,可以当做板子打. 根据二分图博弈,如果一个点x在某种方案中不属于最大匹配,那么这是一个先手必败点. 因为对方先手,因此我们就是要找这样 ...

  5. BZOJ2331:[SCOI2011]地板——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2331 题面复制于洛谷 题目描述 lxhgww的小名叫”小L“,这是因为他总是很喜欢L型的东西.小L家 ...

  6. Function.caller, arguments.caller, arguments.callee, arguments.callee.calller

    Function.caller指向当前函数的调用者,是arguments.caller的替代者 arguments.caller也是指向当前函数的调用者,已被废弃 arguments.callee是对 ...

  7. LibreOJ #541. 「LibreOJ NOIP Round #1」七曜圣贤(单调队列)

    被以前自己瞎YY的东西坑了T T...单调队列的确是可以维护这种操作的.... 显然这题可以转化成维护不在车上的东西的最小值, 支持插入和删去最早出现的值,然后就可以用单调队列了T T #includ ...

  8. [IOI2013]Dreaming

    link 一道非常类似的题目(link) 试题大意 给你一棵含有$n$个节点的有边权森林,问每次连边将会用$L$的代价,问你若此图通过加边成为树时的最小直径.$n \leq 5\times 10^5$ ...

  9. 【数据结构】【平衡树】treap

    之前写treap的传送门 之前写的那个太毒瘤了,这次放一个更毒瘤的指针版上来 #include<cstdio> #include<iostream> #define rg re ...

  10. jq从数组中删除指定元素(根据自定义条件) 超好用的 $.grep() 方法

    转: jQuery.grep() 什么是jQuery.grep()? jQuery.grep()是一个查找满足过滤函数的数组元素的函数.原始数组不受影响,返回值为数组. 用法介绍: 写法: jQuer ...