04-iOS多线程 | GCD

45 阅读4分钟
  • 串行队列 DISPATCH_QUEUE_SERIAL
dispatch_queue_t queue = dispatch_queue_create("task.serial.queue", DISPATCH_QUEUE_SERIAL);
  • 并发队列 DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t queue = dispatch_queue_create("task.serial.queue", DISPATCH_QUEUE_CONCURRENT);
  • 全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  • 主队列
dispatch_queue_t queue = dispatch_get_main_queue();
  • 同步任务
dispatch_sync(queue, ^{
    // 同步任务
})
  • 异步任务
dispatch_async(queue, ^{
    // 异步任务
})
几种执行方式
  • 同步任务 + 并发队列
dispatch_queue_t queue = dispatch_queue_create("task.serial.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
    NSLog(@"1 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"2 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"3 - %@",[NSThread currentThread]);
});
#打印
1 - <_NSMainThread: 0x600001b6c800>{number = 1, name = main}
2 - <_NSMainThread: 0x600001b6c800>{number = 1, name = main}
3 - <_NSMainThread: 0x600001b6c800>{number = 1, name = main}

结论: 虽然是并发队列,但是由于是同步任务,不会开启新的线程,只能依次按顺序执行

  • 异步任务 + 并发队列
dispatch_queue_t queue = dispatch_queue_create("task.serial.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"1 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"2 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"3 - %@",[NSThread currentThread]);
});
#打印
2 - <NSThread: 0x60000024c140>{number = 3, name = (null)}
1 - <NSThread: 0x60000021cd80>{number = 5, name = (null)}
3 - <NSThread: 0x600000250340>{number = 6, name = (null)}

结论: 开辟新的线程,没有安顺序执行

  • 同步任务 + 串行队列
dispatch_queue_t queue = dispatch_queue_create("task.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
    NSLog(@"1 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"2 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"3 - %@",[NSThread currentThread]);
});
#打印
1 - <_NSMainThread: 0x600000654880>{number = 1, name = main}
2 - <_NSMainThread: 0x600000654880>{number = 1, name = main}
3 - <_NSMainThread: 0x600000654880>{number = 1, name = main}

结论: 没有开辟线程,按顺序在主线程执行

  • 异步任务 + 串行队列
dispatch_queue_t queue = dispatch_queue_create("task.serial.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
    NSLog(@"1 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"2 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"3 - %@",[NSThread currentThread]);
});
#打印
1 - <NSThread: 0x60000176e980>{number = 4, name = (null)}
2 - <NSThread: 0x60000176e980>{number = 4, name = (null)}
3 - <NSThread: 0x60000176e980>{number = 4, name = (null)}

结论: 开辟新的线程,按顺序执行

  • 同步执行 + 主队列
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
    NSLog(@"1 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"2 - %@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
    NSLog(@"3 - %@",[NSThread currentThread]);
});

⚠️ 如果在主线程中 同步执行+住队列,会直接锁死;在其他线程中则会到主线程中顺序执行

-(void)test
{
    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:NULL];
}

-(void)run
{
    NSLog(@"0 - %@",[NSThread currentThread]);
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"1 - %@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2 - %@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"3 - %@",[NSThread currentThread]);
    });
}
#打印
0 - <NSThread: 0x600003ccc8c0>{number = 7, name = (null)}
1 - <_NSMainThread: 0x600003cd4800>{number = 1, name = main}
2 - <_NSMainThread: 0x600003cd4800>{number = 1, name = main}
3 - <_NSMainThread: 0x600003cd4800>{number = 1, name = main}
  • 异步执行 + 主队列
NSLog(@"%@ -- begin",[NSThread currentThread]);
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
    NSLog(@"1 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"2 - %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"3 - %@",[NSThread currentThread]);
});
NSLog(@"%@ -- end",[NSThread currentThread]);
#打印
<_NSMainThread: 0x6000033b8800>{number = 1, name = main} -- begin
<_NSMainThread: 0x6000033b8800>{number = 1, name = main} -- end
1 - <_NSMainThread: 0x6000033b8800>{number = 1, name = main}
2 - <_NSMainThread: 0x6000033b8800>{number = 1, name = main}
3 - <_NSMainThread: 0x6000033b8800>{number = 1, name = main}

结论: 没有开辟线程,异步任务在主线程中按顺序执行

  • GCD线程间通信
// 全局并发队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 主队列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_sync(mainQueue, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
});
GCD的一些其他方法
  • 栅栏任务
dispatch_queue_t queue = dispatch_queue_create("barrier.queue.concurrent", DISPATCH_QUEUE_CONCURRENT);
    
dispatch_async(queue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务1 - %@",[NSThread currentThread]);
});
    
dispatch_async(queue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务2 - %@",[NSThread currentThread]);
});
    
dispatch_barrier_async(queue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"栅栏任务 - %@",[NSThread currentThread]);
});
    
dispatch_async(queue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务3 - %@",[NSThread currentThread]);
});
    
dispatch_async(queue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务4 - %@",[NSThread currentThread]);
});
#打印
任务2 - <NSThread: 0x600003828bc0>{number = 8, name = (null)}
任务1 - <NSThread: 0x600003878880>{number = 4, name = (null)}
栅栏任务 - <NSThread: 0x600003878880>{number = 4, name = (null)}
任务3 - <NSThread: 0x600003878880>{number = 4, name = (null)}
任务4 - <NSThread: 0x600003828bc0>{number = 8, name = (null)}

结论: 栅栏任务把一个并发异步队列分成两段,在栅栏任务之前的先执行,然后栅栏任务在执行,最后在执行栅栏任务后面的任务.

  • 延时执行
NSLog(@"begin - %@",[NSThread currentThread]);
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)2.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    NSLog(@"after - %@",[NSThread currentThread]);
});
  • 只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSLog(@"任务 - %@",[NSThread currentThread]);
});
  • 快速迭代
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"begin - %@",[NSThread currentThread]);
dispatch_apply(6, queue, ^(size_t iteration) {
    NSLog(@"%zu - %@",iteration,[NSThread currentThread]);
});
NSLog(@"end - %@",[NSThread currentThread]);
#打印
begin - <_NSMainThread: 0x60000191c800>{number = 1, name = main}
0 - <_NSMainThread: 0x60000191c800>{number = 1, name = main}
1 - <NSThread: 0x600001906f80>{number = 7, name = (null)}
2 - <NSThread: 0x600001944080>{number = 6, name = (null)}
3 - <_NSMainThread: 0x60000191c800>{number = 1, name = main}
4 - <NSThread: 0x600001906f80>{number = 7, name = (null)}
5 - <NSThread: 0x600001944080>{number = 6, name = (null)}
end - <_NSMainThread: 0x60000191c800>{number = 1, name = main}

结论: 类似于遍历, 在begin和end之间执行,会开辟新线程执行任务,效率会加快

  • dispatch_group_t
NSLog(@"begin - %@",[NSThread currentThread]);
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, globalQueue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务1 - %@",[NSThread currentThread]);
});
dispatch_group_async(group, globalQueue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务2 - %@",[NSThread currentThread]);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务3 - %@",[NSThread currentThread]);
    NSLog(@"end - %@",[NSThread currentThread]);
});
#打印
begin - <_NSMainThread: 0x600003f38880>{number = 1, name = main}
任务1 - <NSThread: 0x600003f70d00>{number = 6, name = (null)}
任务2 - <NSThread: 0x600003f7d440>{number = 5, name = (null)}
任务3 - <_NSMainThread: 0x600003f38880>{number = 1, name = main}
end - <_NSMainThread: 0x600003f38880>{number = 1, name = main}

结论: 多个异步并发队列执行结束后在执行主线程任务

  • dispatch_group_wait
NSLog(@"begin - %@",[NSThread currentThread]);
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, globalQueue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务1 - %@",[NSThread currentThread]);
});
dispatch_group_async(group, globalQueue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务2 - %@",[NSThread currentThread]);
});
// 等待上面任务完成后在执行下面任务
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"任务3 - %@",[NSThread currentThread]);
NSLog(@"end - %@",[NSThread currentThread]);
#打印
begin - <_NSMainThread: 0x60000302c880>{number = 1, name = main}
任务1 - <NSThread: 0x60000303c1c0>{number = 6, name = (null)}
任务2 - <NSThread: 0x60000307c600>{number = 7, name = (null)}
任务3 - <_NSMainThread: 0x60000302c880>{number = 1, name = main}
end - <_NSMainThread: 0x60000302c880>{number = 1, name = main}

结论: dispatch_group_wait 相当于阻塞当前线程,等之前的任务完成后在走下面的任务

  • dispatch_group_enter ,dispatch_group_leave
NSLog(@"begin - %@",[NSThread currentThread]);
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务1 - %@",[NSThread currentThread]);
    dispatch_group_leave(group);
});
    
dispatch_group_enter(group);
dispatch_async(globalQueue, ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务2 - %@",[NSThread currentThread]);
    dispatch_group_leave(group);
});
    
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    [NSThread sleepForTimeInterval:1.0];
    NSLog(@"任务3 - %@",[NSThread currentThread]);
    NSLog(@"end - %@",[NSThread currentThread]);
});
begin - <_NSMainThread: 0x600000b4c800>{number = 1, name = main}
任务2 - <NSThread: 0x600000b090c0>{number = 3, name = (null)}
任务1 - <NSThread: 0x600000b101c0>{number = 5, name = (null)}
任务3 - <_NSMainThread: 0x600000b4c800>{number = 1, name = main}
end - <_NSMainThread: 0x600000b4c800>{number = 1, name = main}

结论: dispatch_group_notify 之前的任务完成后在执行dispatch_group_notify的任务