浅谈iOS多线程
浅谈iOS多线程
首先,先看看进程和线程的概念。
图1.1
这一块不难理解,重点点下他们的几个重要区别:
1,地址空间和资源:进程可以申请和拥有系统资源,线程不行。资源进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
2,通信:进程间需要用到IPC(这个可以谁总结开个课),线程可以直接读写进程的数据段来通信(需要涉及锁,下面会简单讲到)。
3,调度和切换:线程快,进程慢。
好了,切回主题,iOS多线程技术,一般有三个,NSThread,NSOperation/NSOperationQueue,GCD(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 提供 addOperation和addOperationWithBlock方法 名字取得很好,一眼就可以看出用法了,前者用来添加任务,后者用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_SERIAL
串
DISPATCH_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多线程的更多相关文章
- 浅谈iOS视频开发
浅谈iOS视频开发 这段时间对视频开发进行了一些了解,在这里和大家分享一下我自己觉得学习步骤和资料,希望对那些对视频感兴趣的朋友有些帮助. 一.iOS系统自带播放器 要了解iOS视频开发,首先我们从 ...
- 浅谈iOS中的userAgent
浅谈iOS中的userAgent User-Agent(用户代理)字符串是Web浏览器用于声明自身型号版本并随HTTP请求发送给Web服务器的字符串,在Web服务器上可以获取到该字符串. 在公司产 ...
- 浅谈iOS需要掌握的技术点
鉴于很多人的简历中的技术点体现(很多朋友问我iOS需要知道注意哪些)! 技术点: 1.热更新 (及时解决线上问题) 2.runtime(json解析.数据越界.扩大button点击事件.拦截系统方法) ...
- 浅谈iOS中MVVM的架构设计与团队协作
说到架构设计和团队协作,这个对App的开发还是比较重要的.即使作为一个专业的搬砖者,前提是你这砖搬完放在哪?不只是Code有框架,其他的东西都是有框架的,比如桥梁等等神马的~在这儿就不往外扯了.一个好 ...
- IOS中 浅谈iOS中MVVM的架构设计与团队协作
今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
- 浅谈 iOS 与 H5 的交互- JavaScriptCore 框架
前言 小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCo ...
- 浅谈iOS中MVVM的架构设计与团队协作【转载】
今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...
- 浅谈iOS开发的协议(protocol)和代理(delegate)
协议和代理对于一个新手来说确实不讨好理解,也有很多的iOS开发的老手对此是懂非懂的.网上的很多博文只是讲了怎么使用,并没有说的很明白.下面我谈一下我的理解. 1.你要先搞明白,协议和代理为什么会出现, ...
- 浅谈iOS程序员的成长和进阶
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
随机推荐
- week1day01 认识python 变量 数据类型 条件if语句
1.什么是python? Python是一种解释型.面向对象.动态数据类型的高级程序设计语言.Python由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991年.像Pe ...
- Educational Codeforces Round 33 (Rated for Div. 2) 题解
A.每个状态只有一种后续转移,判断每次转移是否都合法即可. #include <iostream> #include <cstdio> using namespace std; ...
- NOIP2017 逛公园 题解报告 【最短路 + 拓扑序 + dp】
题目描述 策策同学特别喜欢逛公园.公园可以看成一张NNN个点MMM条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,NNN号点是公园的出口,每条边有一个非负权值, 代表策策经过这条边所要花 ...
- redis的自带VM(虚拟内存)
Redis支持采用VM技术,以达到当数据超过设置的可使用的物理内存的时候能够正常运行.当数据超过物理内存的时候,把一部分数据写入磁盘中的一块空间来代替物理内存. vm-enabled no ...
- 并发时-修改Linux系统下的最大文件描述符限制
通常我们通过终端连接到linux系统后执行ulimit -n 命令可以看到本次登录的session其文件描述符的限制,如下: $ulimit -n1024 当然可以通过ulimit -SHn 1024 ...
- Spark集群基础概念 与 spark架构原理
一.Spark集群基础概念 将DAG划分为多个stage阶段,遵循以下原则: 1.将尽可能多的窄依赖关系的RDD划为同一个stage阶段. 2.当遇到shuffle操作,就意味着上一个stage阶段结 ...
- 课程14:get和post是神马
http://www.codeschool.cn/lesson/14.html get和post是神马? get和post是http中两种最常用到的请求类型 简单理解get请求 get请求多用于获取信 ...
- 洛谷P1434 滑雪
题目描述 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一个区域中最长 ...
- socketpair + signal + select 的套路
1:起因 最近在看代码时连续两次看到这三个函数的组合使用,为方便以后借鉴和回忆,先记录下来. 这三个函数的应用场景是这样的: 1.1 首先socketpair函数创建一对已连接套接字,返回的两个描述符 ...
- 手脱nSPack 3.7
方法一: 1. OD查壳—nSpack3.7的壳 2. 载入OD 看起来很眼熟,F8一次,然后下面就可以使用ESP定律了,使用ESP定律下断点,然后F9四次 3. F9四次后落到这个位置 接下 ...