浅谈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. EF中Json序列化对象时检测到循环引用的解决办法

    MVC4 EF中将数据表外键引用的是自身,转换成Json时,总是提示错误:“序列化类型为....的对象时检测到循环引用.”: 解决办法: 把要序列化的对象转为匿名对象去掉导航属性,如下 :本来是var ...

  2. HDU4055_Number String

    题目告诉你在一个排列中,相邻两个数的大小关系.问你排列可能有多少种情况. DP. f[i][j]表示将i个数按照前面i-1个大小关系排列且最后一个数位j的排列数有多少个. 这样对于新加入的一个数i+1 ...

  3. Ajax请求会话过期处理(JS)

    对于页面来说,处理session过期比较简单,一般只需在过滤器里面判断session用户是否存在,不存在则跳转页面到登陆页即可. 对于Ajax请求来说,这个办法则无效,只能获取到登录页的html代码. ...

  4. Linux内核分析第七周———可执行程序的装载

    Linux内核分析第七周---可执行程序的装载 李雪琦+原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/US ...

  5. git用户名和邮箱配置

    1. 设置全局用户名和邮箱 git config --global user.name "xxx" git config --global user.email "xxx ...

  6. bzoj4584

    escription 在首尔城中,汉江横贯东西.在汉江的北岸,从西向东星星点点地分布着个划艇学校,编号依次为到.每个学校都 拥有若干艘划艇.同一所学校的所有划艇颜色相同,不同的学校的划艇颜色互不相同. ...

  7. 【poj2068】Nim

    Portal -->poj2068 Description ​  给你\(S\)个石子,有\(2n\)个人分成两队,编号为奇数的一队,编号为偶数的一队,\(2n\)个人按照编号从小到大的顺序拿石 ...

  8. golang字符串常用函数

    package utils import "fmt" import "strconv" import "strings" var str s ...

  9. 如何将下载的web工程导入到eclipse中使用

    如果你是喜欢编程的,在你的开发工具中一定有许多项目,就像小编一样(PS:小编只想默默地装一X):   我们选中其中的一个项目,然后[Ctrl + C]复制,再[Ctrl + V]粘贴到桌面:   那么 ...

  10. 前端PHP入门-035-Session的实例

      登陆例子:(请注意一定要自己敲一遍,不要CV大法) 首先上一下成果图,激起同学们写的欲望,登录页如下: 点击登陆之后如下: 说明哦了,么问题.接下来自己实现一下. 首先数据库信息: 新建一个名为 ...