美文网首页
GCD的相关使用

GCD的相关使用

作者: 脚踏实地的小C | 来源:发表于2021-06-08 14:40 被阅读0次

一、同步执行 + 主队列

/**
 * 同步执行 + 主队列
 * 特点(主线程调用):互等卡主不执行。
 * 特点(其他线程调用):不会开启新线程,执行完一个任务,再执行下一个任务。
 */
- (void)syncMain {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600001904240>{number = 1, name = main}
开启

线程死锁。为什么呢?
- (void)syncMain {} ----> 任务AGCD同步任务 ----> 任务B
      任务A在主队列,并且已经开始执行(打印出currentThread),这个时候任务B被加入到主队列中,并且同步执行,且不能开新的线程。
      任务B得等Block函数执行完成,才能返回,然而主队列是串行的,得等任务A执行完才能去执行任务B的Block。
      造成了任务A在等任务B完成才能继续执行,但是串行队列中,又不能让任务B在任务A未完成之前开始执行,相互等待,造成了死锁。

二、同步执行 + 并发队列

/**
 * 同步执行 + 并发队列
 * 特点:在当前线程中执行任务,不会开启新线程,执行完一个任务,再执行下一个任务。
 */
- (void)syncConcurrent {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("syncConcurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600003e0c1c0>{number = 1, name = main}
开启
1---<NSThread: 0x600003e0c1c0>{number = 1, name = main}
2---<NSThread: 0x600003e0c1c0>{number = 1, name = main}
结束

三、异步执行 + 并发队列

/**
 * 异步执行 + 并发队列
 * 特点:可以开启多个线程,任务交替(同时)执行。
 */
- (void)asyncConcurrent {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("asyncConcurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600000d48980>{number = 1, name = main}
开启
结束
1---<NSThread: 0x600000d019c0>{number = 5, name = (null)}
2---<NSThread: 0x600000d00500>{number = 6, name = (null)}

四、同步执行 + 串行队列

/**
 * 同步执行 + 串行队列
 * 特点:不会开启新线程,在当前线程执行任务。任务是串行的,执行完一个任务,再执行下一个任务。
 */
- (void)syncSerial {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("syncSerial", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x600001284240>{number = 1, name = main}
开启
1---<NSThread: 0x600001284240>{number = 1, name = main}
2---<NSThread: 0x600001284240>{number = 1, name = main}
结束

五、异步执行 + 串行队列

/**
 * 异步执行 + 串行队列
 * 特点:会开启新线程,但是因为任务是串行的,执行完一个任务,再执行下一个任务。
 */
- (void)asyncSerial {
    NSLog(@"currentThread---%@",[NSThread currentThread]);  // 打印当前线程
    NSLog(@"开启");
    
    dispatch_queue_t queue = dispatch_queue_create("asyncConcurrent", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    
    NSLog(@"结束");
}

运行结果:

currentThread---<NSThread: 0x6000025ac580>{number = 1, name = main}
开启
结束
1---<NSThread: 0x6000025fc680>{number = 4, name = (null)}
2---<NSThread: 0x6000025fc680>{number = 4, name = (null)}

六、其他函数用法

1、dispatch_after

- (void)GCDDelay {
    NSLog(@"current_%@",[NSThread currentThread]);
    //主队列延时
    dispatch_time_t when_main = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_main, dispatch_get_main_queue(), ^{
        NSLog(@"main_%@",[NSThread currentThread]);
    });
    
    //全局队列延时
    dispatch_time_t when_global = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_global, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"global_%@",[NSThread currentThread]);
    });
    
    //自定义队列延时
    dispatch_queue_t customeQue = dispatch_queue_create("customeQue", DISPATCH_QUEUE_SERIAL);
    dispatch_time_t when_global_custom = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC));
    dispatch_after(when_global_custom, customeQue, ^{
        NSLog(@"when_global_custom_%@",[NSThread currentThread]);
    });
}
current_<NSThread: 0x600003fe8980>{number = 1, name = main}
main_<NSThread: 0x600003fe8980>{number = 1, name = main}
when_global_custom_<NSThread: 0x600003fa58c0>{number = 7, name = (null)}
global_<NSThread: 0x600003fad280>{number = 5, name = (null)}

      我们可以看到,当队列是主队列时,任务是在主线程执行;当队列为全局或自定义时,任务是在子线程中执行

2、dispatch_once

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    NSLog(@"current_%@",[NSThread currentThread]);
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
}
current_<NSThread: 0x600001cf8900>{number = 1, name = main}
<NSThread: 0x600001cf8900>{number = 1, name = main}

      程序运行期间,只会执行一次打印,任务在主线程中执行

3、dispatch_group_async & dispatch_group_notify

- (void)GCDGroup {
    
    NSLog(@"start_%@",[NSThread currentThread]);
    
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"3---%@",[NSThread currentThread]);
    });
    NSLog(@"end_%@",[NSThread currentThread]);
}
start_<NSThread: 0x6000032a0980>{number = 1, name = main}
end_<NSThread: 0x6000032a0980>{number = 1, name = main}
1---<NSThread: 0x6000032a8880>{number = 6, name = (null)}
2---<NSThread: 0x6000032ed4c0>{number = 3, name = (null)}
3---<NSThread: 0x6000032ed4c0>{number = 3, name = (null)}

dispatch_group_asyncdispatch_get_global_queue时会开辟新的线程执行任务,任务会在子线程中执行
dispatch_group_notify只会在dispatch_group_async都执行完后才会执行

4、dispatch_barrier_async

- (void)GCDBarrier {
    
    NSLog(@"start_%@",[NSThread currentThread]);
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(myQueue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
    });
    dispatch_async(myQueue, ^{
        NSLog(@"2---%@",[NSThread currentThread]);
    });
    //同步sync
    dispatch_barrier_sync(myQueue, ^{
        NSLog(@"barrier---%@",[NSThread currentThread]);
    });
    dispatch_async(myQueue, ^{
        NSLog(@"3---%@",[NSThread currentThread]);
    });
    dispatch_async(myQueue, ^{
        NSLog(@"4---%@",[NSThread currentThread]);
    });
    
    NSLog(@"end_%@",[NSThread currentThread]);
}
myQueue为自定义时:
start_<NSThread: 0x600001044980>{number = 1, name = main}
2---<NSThread: 0x600001008a80>{number = 6, name = (null)}
1---<NSThread: 0x60000104db80>{number = 5, name = (null)}
barrier---<NSThread: 0x600001044980>{number = 1, name = main}
end_<NSThread: 0x600001044980>{number = 1, name = main}
3---<NSThread: 0x60000104db80>{number = 5, name = (null)}
4---<NSThread: 0x600001008a80>{number = 6, name = (null)}

myQueue为:dispatch_get_global_queue(0,0)时
start_<NSThread: 0x600001f90a00>{number = 1, name = main}
barrier---<NSThread: 0x600001f90a00>{number = 1, name = main}
1---<NSThread: 0x600001fdacc0>{number = 6, name = (null)}
2---<NSThread: 0x600001fd5340>{number = 7, name = (null)}
3---<NSThread: 0x600001fdacc0>{number = 6, name = (null)}
end_<NSThread: 0x600001f90a00>{number = 1, name = main}
4---<NSThread: 0x600001fc5080>{number = 4, name = (null)}
  • 当队列为自定义时,使用dispatch_barrier_sync ()后,任务3、4必须等任务1、2执行完后才能执行
  • 当队列是dispatch_get_global_queue(0,0)时,就算使用了dispatch_barrier_sync (),执行顺序随机不固定
  • 当队列是dispatch_get_main_queue()时,死锁

5、dispatch_apply

- (void)GCDApply {
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    //重复执行
    dispatch_apply(5, myQueue, ^(size_t i) {
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
    });
}
myQueue为串行:
start_<NSThread: 0x600003d70980>{number = 1, name = main}
第0次_<NSThread: 0x600003d70980>{number = 1, name = main}
第1次_<NSThread: 0x600003d70980>{number = 1, name = main}
第2次_<NSThread: 0x600003d70980>{number = 1, name = main}
第3次_<NSThread: 0x600003d70980>{number = 1, name = main}
第4次_<NSThread: 0x600003d70980>{number = 1, name = main}
end_<NSThread: 0x600003d70980>{number = 1, name = main}

myQueue为并行:
start_<NSThread: 0x6000009d0a00>{number = 1, name = main}
第3次_<NSThread: 0x600000995900>{number = 6, name = (null)}
第2次_<NSThread: 0x6000009d7540>{number = 4, name = (null)}
第0次_<NSThread: 0x6000009d0a00>{number = 1, name = main}
第1次_<NSThread: 0x600000984300>{number = 7, name = (null)}
第4次_<NSThread: 0x6000009852c0>{number = 5, name = (null)}
end_<NSThread: 0x6000009d0a00>{number = 1, name = main}
  • 用于重复执行某个任务
  • 任务队列是串行队列时,重复执行的任务会按顺序执行
  • 任务队列是并行队列时,重复执行的任务会并发执行

6、dispatch_semaphore_create & dispatch_semaphore_wait & dispatch_semaphore_signal

- (void)GCDSemaphor {
    NSLog(@"start_%@",[NSThread currentThread]);
    
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    //创建信号量,初始值不能小于0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    
    //重复执行
    dispatch_apply(5, myQueue, ^(size_t i) {
        //等待降低信号量,也就是信号量-1
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"第%@次_%@",@(i),[NSThread currentThread]);
        //提高信号量,也就是信号量+1
        dispatch_semaphore_signal(semaphore);
    });
    NSLog(@"end_%@",[NSThread currentThread]);
}
start_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第0次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第1次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第2次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第3次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
第4次_<NSThread: 0x600003bf0bc0>{number = 1, name = main}
end_<NSThread: 0x600003bf0bc0>{number = 1, name = main}

异步任务使用

- (void)GCDSemaphorAsync {
    NSLog(@"start_%@",[NSThread currentThread]);
    
    dispatch_queue_t myQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
    //创建信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    dispatch_async(myQueue, ^{
        NSLog(@"第一次任务开始_%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2];
        NSLog(@"第一次任务结束_%@",[NSThread currentThread]);
        //会将信号量的值加一
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_async(myQueue, ^{
        NSLog(@"第二次任务开始_%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2];
        NSLog(@"第二次任务结束_%@",[NSThread currentThread]);
        //会将信号量的值加一
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    dispatch_async(myQueue, ^{
        NSLog(@"第三次任务开始_%@",[NSThread currentThread]);
        [NSThread sleepForTimeInterval:2];
        NSLog(@"第三次任务结束_%@",[NSThread currentThread]);
        //会将信号量的值加一
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
    NSLog(@"end_%@",[NSThread currentThread]);
}
start_<NSThread: 0x600002eb0a00>{number = 1, name = main}
第一次任务开始_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第一次任务结束_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第二次任务开始_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第二次任务结束_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第三次任务开始_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
第三次任务结束_<NSThread: 0x600002eb9f40>{number = 6, name = (null)}
end_<NSThread: 0x600002eb0a00>{number = 1, name = main}
  • dispatch_semaphore_create创建信号量,初始值不能小于0
  • dispatch_semaphore_wait等待降低信号量,也就是信号量-1
  • dispatch_semaphore_signal提高信号量,也就是信号量+1
  • dispatch_semaphore_waitdispatch_semaphore_signal通常配对使用
主要作用:
  • 保持线程同步,将异步执行任务转换为同步执行任务
  • 保证线程 安全,为线程加锁

相关文章

网友评论

      本文标题:GCD的相关使用

      本文链接:https://www.haomeiwen.com/subject/mevosltx.html