整理一些多线程相关的知识。
并行 & 并发
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 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 *invocationOperation = [[
NSInvocationOperation alloc] initWithTarget:
self selector:
@selector(invocationOperation) object:
nil];
[invocationOperation start];
NSBlockOperation * blockOperation = [
NSBlockOperation blockOperationWithBlock:^{
NSLog(
@"blockOperation:%@",[
NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
NSLog(
@"addExecutionBlock:%@",[
NSThread currentThread]);
}];
[blockOperation start];
- (
void)invocationOperation {
NSLog(
@"invocationOperation:%@",[
NSThread currentThread]);
}
|
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 *invocationOperation = [[
NSInvocationOperation alloc] initWithTarget:
self selector:
@selector(invocationOperation) object:
nil];
NSBlockOperation * blockOperation = [
NSBlockOperation blockOperationWithBlock:^{
NSLog(
@"blockOperation:%@",[
NSThread currentThread]);
}];
[operationQueue addOperation:invocationOperation];
[operationQueue addOperation:blockOperation];
- (
void)invocationOperation {
NSLog(
@"invocationOperation:%@",[
NSThread currentThread]);
}
|
也可以直接添加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]);
}];
|
可以通过 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 * blockOperation0 = [
NSBlockOperation blockOperationWithBlock:^{
NSLog(
@"blockOperation0:%@",[
NSThread currentThread]);
}];
NSBlockOperation * blockOperation1 = [
NSBlockOperation blockOperationWithBlock:^{
sleep(
1);
NSLog(
@"blockOperation1:%@",[
NSThread currentThread]);
}];
[blockOperation0 addDependency:blockOperation1];
[operationQueue addOperation:blockOperation0];
[operationQueue addOperation:blockOperation1];
|
注意: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);
});
|
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);
});
|
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_once
一般会以这种形式出现
1
2
3
4
5
|
static
dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(
@"dispatch_once task...");
});
|
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");
|
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_wait(group, DISPATCH_TIME_FOREVER);
NSLog(
@"wait");
|
总结
当遇到相应场景的时候,知道使用哪种方法比较合理就行了。