GCD

2017-04-19  本文已影响82人  ibiaoma

本文摘录其他文章所写

1、队列和线程的关系

对我们使用者来说,与其说GCD是面向线程的,不如说是面向队列的。 它隐藏了内部线程的调度。
我们所做的仅仅是创建不同的队列,把Block追加到队列中去执行,而队列是FIFO(先进先出)的。
它会按照我们追加的Block的顺序,在综合我们调用的gcd的api(sync、async、dispatch_barrier_async等等),以及根据系统负载来增减线程并发数, 来调度线程执行Block。

例一:我们在主线程中,往一个并行queue,以sync的方式提交了一个Block,结果Block在主线程中执行。

dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue1, ^{
    NSLog(@"%@",[NSThread currentThread]);
});
输出结果:{number = 1, name = main}

例二:我们在主线程中用aync方式提交一个Block,结果Block在分线程中执行。

dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
    NSLog(@"%@",[NSThread currentThread]);
});
输出结果:{number = 2, name = (null)}

例三:我们分别用sync和async向主队列提交Block,结果Block都是在主线程中执行:
注意:我们不能直接在主线程用sync如下的形式去提交Block,否则会引起死锁:

    dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"%@",[NSThread currentThread]);
});

我们用sync如下的方式去提交Block:

dispatch_queue_t queue1 = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue1, ^{
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"%@",[NSThread currentThread]);
    });
});
输出结果:{number = 1, name = main}

dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"%@",[NSThread currentThread]);
});
输出结果:{number = 1, name = main}

总结一下:

需要注意以下两点:

2、GCD的死锁

简单举个死锁例子:

dispatch_sync(dispatch_get_main_queue(), ^{
    NSLog(@"任务一");
});
NSLog(@"任务二");

原因是并行队列中任务一虽被提交仍然是在queue的队尾,在任务二之后,但是因为是并行的,所以任务一并不会一直等任务二结束才去执行,而是直接执行完。此时任务二的因为任务一的结束,sync阻塞也就消除,任务二得以执行。

一些sync的阻塞机制:

总结一下,会引起GCD死锁的行为:

3、4个GCD方法的区别:

dispatch_async(, )
dispatch_sync(, )
dispatch_barrier_async(, )
dispatch_barrier_sync(, )

这样写操作的时候,始终只有它这一条线程在进行。而读操作一直是并行的。这么做充分利用了多线程的优势,还不需要加锁,减少了相当一部分的性能开销。实现了读写操作的线程安全。

而dispatch_barrier_sync可以阻塞并行队列(栅栏作用的体现):

    dispatch_queue_t queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
    dispatch_barrier_sync(queue, ^{
        dispatch_async(queue, ^{
            NSLog(@"任务二");
        });
        dispatch_async(queue, ^{
            NSLog(@"任务三");
        });
        //睡眠2秒
        [NSThread sleepForTimeInterval:2];
        NSLog(@"任务一");
    });
    输出结果 :
    任务一
    任务二
    任务三
上一篇 下一篇

猜你喜欢

热点阅读