undefined

IOS 多线程:NSOperation & NSOperationQueue

https://www.jianshu.com/p/d973cd1acc32

IOS 线程

主线程又称为 UI 线程。主线程一般用来刷新 UI 界面,处理 UI 事件(比如:点击、滚动、拖拽等事件)。不要将耗时的操作放在主线程

1. 创建多线程的技术

  • pthread:c语言的,跨平台,适用于 Unix/Linux/Windows等系统。线程生命周期需要程序员管理。使用难度大
  • NSThread:OC语言的,面向对象,直接操作线程对象,程序猿管理线程生命周期
  • GCD:充分利用设备的多核,C语言,自动管理线程生命周期。
  • NSOperation:OC 语言,底层是 GCD,面对对象,自动管理线程生命周期。

二、GCD 使用

Grand Central Dispatch ,纯 C 语言。GCD 会自动利用更多的 CPU 内核,GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

GCD 队列分为并发队列(dispatch_async)、串行队列(dispatch_sync)

1. 主队列

异步任务:不开线程,有序执行,主队列特点:先执行完主线程上的代码,才会执行主队列中的任务。主队列又叫做全局串行队列

同步执行:如果在主线程上执行,则会死锁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (void)demo5 {
// 主队列,异步执行,任务有序执行,不会开新线程
// 主队列特点:先执行完主线程上的代码,才会执行主队列中的任务
for (int i = 0;i < 10; i++) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"%d %@", i, [NSThread currentThread]);
});
}
}
- (void)demo6 {
// 主队列,同步执行,如果在主线程上会死锁,无法执行
for (int i = 0;i < 10; i++) {
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%d %@", i, [NSThread currentThread]);
});
}
}

2. 全局队列

本质就是并发队列。区别

  • 并发队列有名称,可以跟踪错误,全局队列没有
  • 并发队列是 create 创建出来的,在 MRC 中就需要 release。全局队列不需要 release
  • 一般使用全局队列
1
2
3
dispatch_get_global_queue(intptr_t identifier, uintptr_t flags)
identifier: 优先级(服务质量)
flags:没有用,填 0 即可

3. 同步任务

很多事情都有先后顺序

4. 队列之间对比

全局并行队列 手动创建串行队列 主队列
同步(sync) 没有开启新线程
串行执行任务
没有开启新线程
串行执行任务
会死锁
异步(async) 有开启新线程
并行执行任务
有开启新线程
串行执行任务
没有开启新线程
串行执行任务

5. Barrier

主要用于在多个异步操作完成之后,统一对非线程安全的对象进行更新。

等待队列中所有任务执行完成,才会执行 barrier 中的代码

1
2
3
4
5
6
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_barrier_async(dispatch_get_global_queue(0,0), ^{
[self.array addObject:[NSNumber numberWithInt:index]];
NSLog(@"add number: %d", index);
});
});

6. 延迟执行和一次性执行

1
2
dispatch_after
dispatch_once

三、NSOperation 使用

NSOperation 是一个抽象类,NSOperation 的子类:NSInvocationOperation、NSBlockOperation、自定义 operation

NSOperation 和 NSOpertionQueue 实现多线程的具体步骤:

  • 先将需要执行的操作封装到一个 NSOperation 对象中
  • 然后将 NSOperation 对象添加到 NSOperationQueue 中
  • 系统会自动将 NSOperationQueue 中的 NSOperation 取出来,将取出来的 NSOperation 封装的操作放到一条新线程中执行

1.NSInvocationOperation 使用

  • start 方法的更新操作的状态,然后调用 main 方法。不会开启新线程,是在主线程上调用的

  • 也可以加入到队列中执行,是在子线程上调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSInvocationOperation* op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(demo) object:nil];
    // [op start];
    NSOperationQueue* queue = [[NSOperationQueue alloc]init];
    [queue addOperation:op];
    }
    - (void)demo {
    NSLog(@"cur thread: %@", [NSThread currentThread]);
    }

2. NSBlockOperation 使用

默认 并发队列、异步执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 创建队列
NSOperationQueue* queue = [[NSOperationQueue alloc]init];
// 创建操作
NSBlockOperation* op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"cur thread: %@", [NSThread currentThread]);
}];
// 操作完成之后执行
[op setCompletionBlock:^{
NSLog(@"end");
}];
[queue addOperation:op];

// 第二种方法
NSOperationQueue* queue = [[NSOperationQueue alloc]init];
[queue addOperationWithBlock:^{
NSLog(@"cur thread: %@", [NSThread currentThread]);
}];
}

3. 线程间通信

1
2
3
4
5
6
7
8
9
[self.queue addOperationWithBlock:^{
NSLog(@"child thread: %@", [NSThread currentThread]);

// 线程间通信,回到主线程
// 主队列
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"main thread: %@", [NSThread currentThread]);
}];
}];

3. Barrier 阻塞

主要用于在多个异步操作完成之后,统一对非线程安全的对象进行更新。适合于大规模的 IO 操作。

当访问数据库或文件的时候,更新数据的时候不能和其他更新或读取的操作在同一时间执行,使用 dispatch_barrier_async 解决。

4. 其他

1
2
// 设置最大并发数 
_queue.maxConcurrentOperationCount = 2;

三、NSOperation 和 GCD 的对比

GCD:

  • GCD 是IOS 4.0 推出的,主要针对多核 CPU 做了优化,是 C 语言的技术
  • GCD 是将任务(block)添加到队列(串行、并行、全局、主队列),并且以同步、异步的方式执行任务的函数
  • GCD 提供了一些 NSOperation 不具备的功能
    • 一次性执行
    • 延迟执行
    • 调度组

NSOperation

  • NSOperation 是 IOS2.0 推出的,IOS4 之后重写了 NSOperation
  • NSOperation 将操作(异步的任务)添加到队列(并发队列),就会执行指定操作的函数
  • NSOperation 里提供的方便的操作
    • 最大并发数
    • 队列的暂停、继续
    • 取消所有操作
    • 取消操作之间的依赖关系(GCD可以用同步实现)