整理一些多线程相关的知识。
并行 & 并发
1、并行:并行是相对于多核而言的,几个任务同时执行。
2、并发:并发是相对于单核而言的,几个任务之间快速切换运行,看起来像是“同时”发生的一样
NSThread
优点:轻量级
缺点:需要手动管理线程活动,如生命周期、线程同步、睡眠等。
搭配runloop实现常驻线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
[thread start];
- (void)threadRun {
@autoreleasepool {
NSLog(@"threadRun");
// NSTimer *timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timeTask) userInfo:nil repeats:YES];
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timeTask) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
}
- (void)timeTask {
NSLog(@"timeTask:%@",[NSThread currentThread]);
}
|
NSOperation & NSOperationQueue
NSOperation
NSOperation 是一个抽象类,只能使用它的自类来进行操作。系统为我们创建了两个子类NSInvocationOperation & NSBlockOperation。
直接使用这两个类执行任务,系统不会创建子线程,而是在当前线程执行任务。NSBlockOperation 使用 addExecutionBlock方法的任务是在多线程执行的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//NSInvocationOperation
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
[invocationOperation start];
//NSBlockOperation
NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperation:%@",[NSThread currentThread]);
}];
//这里面的任务是多线程执行的
[blockOperation addExecutionBlock:^{
NSLog(@"addExecutionBlock:%@",[NSThread currentThread]);
}];
[blockOperation start];
- (void)invocationOperation {
NSLog(@"invocationOperation:%@",[NSThread currentThread]);
}
//invocationOperation:<NSThread: 0x60800007e1c0>{number = 1, name = main}
//blockOperation:<NSThread: 0x60800007e1c0>{number = 1, name = main}
//addExecutionBlock:<NSThread: 0x608000078800>{number = 3, name = (null)}
|
NSOperationQueue
//主队列,任务在主线程执行,一般用于更新UI的时候使用。
NSOperationQueue queue = [NSOperationQueue mainQueue];
//子队列,任务在子线程执行,用于处理耗时任务。
NSOperationQueue queue = [[NSOperationQueue alloc] init];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
//NSInvocationOperation
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
//NSBlockOperation
NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperation:%@",[NSThread currentThread]);
}];
[operationQueue addOperation:invocationOperation];
[operationQueue addOperation:blockOperation];
- (void)invocationOperation {
NSLog(@"invocationOperation:%@",[NSThread currentThread]);
}
// invocationOperation:<NSThread: 0x60c00046b940>{number = 4, name = (null)}
// blockOperation:<NSThread: 0x60800026b580>{number = 3, name = (null)}
|
也可以直接添加block
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
[operationQueue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
[operationQueue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
[operationQueue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
// <NSThread: 0x6080002637c0>{number = 4, name = (null)}
// <NSThread: 0x60c0002667c0>{number = 5, name = (null)}
// <NSThread: 0x60000047b2c0>{number = 3, name = (null)}
|
可以通过 maxConcurrentOperationCount 来控制最大并发数,当最大并发数为1时,就相当于串行队列
NSOperation添加依赖关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
//NSBlockOperation
NSBlockOperation * blockOperation0 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"blockOperation0:%@",[NSThread currentThread]);
}];
NSBlockOperation * blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"blockOperation1:%@",[NSThread currentThread]);
}];
//blockOperation0 依赖 blockOperation1,只有在 blockOperation1 执行完成才能执行 blockOperation0
[blockOperation0 addDependency:blockOperation1];
[operationQueue addOperation:blockOperation0];
[operationQueue addOperation:blockOperation1];
//blockOperation1:<NSThread: 0x600000269c80>{number = 3, name = (null)}
//blockOperation0:<NSThread: 0x60c000479040>{number = 4, name = (null)}
|
注意:NSOperationQueue 是非线程安全的,多个线程访问统一资源时,需要加锁。
1
2
3
4
5
|
self.lock = [[NSLock alloc] init];
[self.lock lock];
//不能同时访问的资源
[self.lock unlock];
|
GCD
创建队列,然后再往队列添加任务。也可以直接使用系统创建的队列。
1
2
3
4
5
6
7
8
|
//创建串行队列
dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_SERIAL);
//创建并发队列
dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
//获取主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//获取全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
创建同步、异步任务
1
2
3
4
5
6
7
|
dispatch_sync(queue, ^{
//同步执行
});
// 异步执行任务创建方法
dispatch_async(queue, ^{
//异步执行
});
|
GCD常用方法
dispatch_barrier
只有当添加在dispatch_barrier前面的任务完成了,才开始执行dispatch_barrier任务。
有两种方式:dispatch_barrier_sync 和 dispat 大专栏 iOS开发之多线程(NSThread、NSOperation、GCD)ch_barrier_async
dispatch_barrier_sync
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"task0.....");
sleep(1);
});
dispatch_async(queue, ^{
NSLog(@"task1.....");
sleep(1);
});
dispatch_barrier_sync(queue, ^{
NSLog(@"task2.....");
sleep(5);
});
NSLog(@"test");
dispatch_async(queue, ^{
NSLog(@"task3.....");
sleep(2);
});
dispatch_async(queue, ^{
NSLog(@"task4.....");
sleep(1);
});
//task0.....
//task1.....
//task2.....
//test....
//task3.....
//task4.....
//只有当task0、task1 执行完才会执行tast2.
//task2 执行完才会往下执行。
//test 执行完后,才会把task3、task4 加进队列.
|
dispatch_barrier_async
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"task0.....");
sleep(1);
});
dispatch_async(queue, ^{
NSLog(@"task1.....");
sleep(1);
});
dispatch_barrier_async(queue, ^{
NSLog(@"task2.....");
sleep(5);
});
NSLog(@"test");
dispatch_async(queue, ^{
NSLog(@"task3.....");
sleep(2);
});
dispatch_async(queue, ^{
NSLog(@"task4.....");
sleep(1);
});
//test....
//task1.....
//task0.....
//task2.....
//task3.....
//task4.....
//test、task0、task1 并发执行。
//task0、task1 执行完才会执行tast2.
//tast2 执行完才会执行tast3、tast4.
|
dispatch_after
1
2
3
4
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"dispatch_after task...");
});
//dispatch_after 会在到了指定的时间之后,将才将任务加到相应的队列中。
|
dispatch_once
一般会以这种形式出现
1
2
3
4
5
|
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"dispatch_once task...");
});
//block里面的任务只会执行一次。
|
dispatch_apply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
dispatch_queue_t queue = dispatch_queue_create("com.vhuichen.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%zu",index);
});
NSLog(@"end");
// 0
// 1
// 3
// 2
// 4
// 5
// 6
// 7
// 8
// 9
// end
// dispatch_apply 会等待所有的任务完成了,才会往下执行。
|
dispatch_semaphore
可以用于线程同步、线程加锁、控制并发线程数量
1
2
3
4
5
6
7
8
9
10
|
//实现同步请求
let semaphoreSignal = DispatchSemaphore(value: 0)
ZBDepthAPI.GET(market: market.name!, succeed: { (depthModel) in
//......
semaphoreSignal.signal()
}) { (error) in
//......
semaphoreSignal.signal()
}
semaphoreSignal.wait()
|
dispatch_group
当需要同时执行多个耗时任务,并且当所有任务执行完后更新UI。那么这时可以使用 dispatch_group 来实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t global = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, global, ^{
NSLog(@"tast0.......");
});
NSLog(@"0");
dispatch_group_async(group, global, ^{
NSLog(@"tast1.......");
});
NSLog(@"1");
dispatch_group_async(group, global, ^{
NSLog(@"tast2.......");
sleep(1);
});
NSLog(@"2");
dispatch_group_enter(group);
dispatch_async(global, ^{
NSLog(@"tast00.......");
dispatch_group_leave(group);
});
// 所有任务完成的时候调用
//dispatch_group_notify(group, global, ^{
// NSLog(@"tast complete...");
//});
//会阻塞当前线程,直到 group 里面的任务全部完成
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"wait");
// 异步加入的任务会立即执行
// dispatch_group_wait会阻塞当前线程,直到 group 里面的任务全部完成
// dispatch_group_enter & dispatch_group_leave 必须成对出现,相当于 dispatch_group_async
|
总结
当遇到相应场景的时候,知道使用哪种方法比较合理就行了。
- iOS开发之多线程技术——NSOperation篇
本篇将从四个方面对iOS开发中使用到的NSOperation技术进行讲解: 一.什么是NSOperation 二.我们为什么使用NSOperation 三.在实际开发中如何使用NSOperation ...
- 【iOS开发】多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用
http://blog.csdn.net/crycheng/article/details/21799611 本篇文章主要介绍下多线程下NSOperation.NSBlockOperation.NSI ...
- iOS中的多线程NSThread/GCD/NSOperation & NSOperationQueue
iOS多线程有四套多线程方案: Pthreads NSThread GCD NSOperation & NSOperationQueue 接下来我来一个一个介绍他们 Pthreads 在类Un ...
- iOS开发之多线程技术
本篇争取一篇讲清讲透,依然将通过四大方面清晰的对iOS开发中多线程的用法进行详尽的讲解: 一.什么是多线程 1)多线程执行原理 2)线程与进程 3)多线程的优缺点 二.我们为什么要用多线程编程技术 三 ...
- iOS开发-多线程编程技术(Thread、Cocoa operations、GCD)
简介 在软件开发中,多线程编程技术被广泛应用,相信多线程任务对我们来说已经不再陌生了.有了多线程技术,我们可以同做多个事情,而不是一个一个任务地进行.比如:前端和后台作交互.大任务(需要耗费一定的时间 ...
- ios开发之多线程---GCD
一:基本概念 1:进程:正在运行的程序为进程. 2:线程:每个进程要想执行任务必须得有线程,进程中任务的执行都是在线程中. 3:线程的串行:一条线程里任务的执行都是串行的,假如有一个进程开辟了一条线程 ...
- iOS开发-多线程开发之线程安全篇
前言:一块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源,比如多个线程访问同一个对象.同一个变量.同一个文件和同一个方法等.因此当多个线程访问同一块资源时,很容易会发生数据错误及数据不安 ...
- 多线程之pthread, NSThread, NSOperation, GCD
关于多线程会有一系列如下:多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD p ...
- iOS多线程开发--NSThread NSOperation GCD
多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势 ...
随机推荐
- win10下载软件防止被杀
很少接触win10,现在需要下载一个软件,但是一直被和谐掉 解决方案: Windows defender 点击病毒和威胁防护 打开定期扫描 找到病毒威胁防护设置 找到排除项 添加排除项 下载成功 但是 ...
- python通过wakeonlan唤醒内网电脑开机
首先需要pip3 install wakeonlan 然后在电脑需要你的网卡支持网络唤醒计算机. 然后在主板BIOS开启支持唤醒. 在系统网卡属性里选上“允许计算机关闭此设备以节约电源”,“允许此设备 ...
- Java的各类型数据在内存中分配情况详解
1. 有这样一种说法,如今争锋于IT战场的两大势力,MS一族偏重于底层实现,Java一族偏重于系统架构.说法根据无从考证,但从两大势力各自的社区力量和图书市场已有佳作不难看出,此说法不虚,但 ...
- POJ-2031 Building a Space Station (球的最小生成树)
http://poj.org/problem?id=2031 Description You are a member of the space station engineering team, a ...
- 分辨率单位及换算,LW / PH、LP / mm、L / mm、Cycles / mm、Cycles / pixel、LP / PH
对于测试数字成像设备非常重要的参数是分辨率.但有不同的方式来表达数码相机的分辨率,有时令人困惑.下面介绍的是是最常见的单位. 百万像素 “这台相机有1000万像素的分辨率”是我们经常在广告上看到的数据 ...
- spark安装和使用
local模式 概述 local模式就是在一台计算机上运行spark程序,通常用于在本机上练手和测试,它将线程映射为worker. 1)local: 所有计算都运行在一个线程当中,没有任何并行计算,通 ...
- Python语言学习前提:循环语句
一.循环语句 1.循环语句:允许执行下一个语句或语句组多次 2. 循环类型 3. 循环控制语句 4. while 循环语句 a.while循环语句:在某个条件下,循环执行某段程序,以处理需要重复处理的 ...
- flask学习笔记1.21
先新建一个文件夹 templates from flask import Flask #创建Flask应用程序实例 #需要传入__name__,作用是为了确定资源所在的路径 app = Flask( ...
- OfficeidMsoViewer最新版
点击下载 OfficeidMsoViewer最新版
- Linux基础篇二:Bash shell(壳,命令解释器)介绍
shell执行方式: 第一:输入命令 (简单工作) 第二: 脚本 (适合大量工作) Bash shell 实际上的叫法是 GNU/Bash 如何查询呢: bash - version ...