GCD1

作者: 霸_霸霸 | 来源:发表于2019-05-10 09:24 被阅读0次

    1. 创建dispatch_queue_t

    需求:我们要打印10000个数字,在打印的同时显示一个红色的视图
    不使用GCD

    - (void)viewDidLoad {
        [super viewDidLoad];
        for (int i = 0; i < 10000; i++) {
                NSLog(@"%d",i);
            }
    
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
        [view setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
        [self.view addSubview:view];
        view.backgroundColor = [UIColor redColor];
    }
    

    上面的代码,所有的操作都是在主线程的,主线程会先把10000个数字打印完再显示图片,这样肯定不是我们想要的;

    使用GCD

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        dispatch_queue_t myQueue = dispatch_queue_create("com.gcd.myQueue1", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(myQueue, ^{
            for (int i = 0; i < 10000; i++) {
                NSLog(@"%d",i);
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"---finished---");
            });
        });
        
        UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
        [view setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
        [self.view addSubview:view];
        view.backgroundColor = [UIColor redColor];
    }
    

    显示图片的同时也在打印数字,这才是我们想要的效果


    2. dispatch_after

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"1s later.");
    });
    

    注意:dispatch_after并不是表示几秒后执行Block中的代码;它表示的是几秒后,将Block追加到指定的Dispatch Queue中。

    我们看下面这段代码

    - (void)viewDidLoad {
        [super viewDidLoad];
        //事件1
        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC));
        dispatch_after(time, dispatch_get_main_queue(), ^{
            NSLog(@"1s later.");
        });
        //事件2
        for (int i = 0; i < 20000; i++) {
            NSLog(@"%d",i);
        }
    }
    

    事件1的代码一般简化为:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            NSLog(@"1s later.");
        });
    

    结果会发现,1s later是在所有的数字打印完了才输出的,而不是固定1s后输出的;这也验证了上面的说法。
    如果要更准确一点,可以把这两个事件分到不同的Queue中执行,互不干涉,互不等待,可以相对准确地来触发定时事件;
    尽管如此,也不能精确地表示一定是1s后执行Block中代码,这涉及到Runloop

    3. dispatch_group

    如果我们希望Queue中的多个处理全部结束后再执行结束处理,我们有2种做法

    • 当只有一个Serial Queue时,可以把所有的处理都追加到Serial Queue中顺序执行即可;当多个处理完成后,再执行结束处理
    • 如果是一个Concurrent Queue,其中的多个处理都是乱序的,我们不知道什么时候能完成所有的处理,所以我们需要一个分隔符,用以确定除结束操作外的所有处理都结束了,我们才可以进行结束处理;dispatch_group就是一个这样的分隔符

    需求:数组array里有30000条数据,不要求数字顺序,全部打印出来即可,打印完成后,输出Read finished.

    1. Serial Queue
    dispatch_queue_t serialQueue = dispatch_queue_create("com.gcd.serialQueue", DISPATCH_QUEUE_SERIAL);
        dispatch_async(serialQueue, ^{
            for (int i = 0; i < 10000; i++) {
                NSLog(@"%@", array[i]);
            }
        });
        dispatch_async(serialQueue, ^{
            for (int i = 10000; i < 20000; i++) {
                NSLog(@"%@", array[i]);
            }
        });
        dispatch_async(serialQueue, ^{
            for (int i = 20000; i < 30000; i++) {
                NSLog(@"%@", array[i]);
            }
        });
        dispatch_async(serialQueue, ^{
            NSLog(@"Read finished.");
        });
    

    结果


    serial.png
    1. Concurrent Queue
    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, concurrentQueue, ^{
            for (int i = 0; i < 10000; i++) {
                NSLog(@"%@",array[i]);
            }
        });
        dispatch_group_async(group, concurrentQueue, ^{
            for (int i = 10000; i < 20000; i++) {
                NSLog(@"%@",array[i]);
            }
        });
        dispatch_group_async(group, concurrentQueue, ^{
            for (int i = 20000; i < 30000; i++) {
                NSLog(@"%@",array[i]);
            }
        });
        
        dispatch_group_notify(group, concurrentQueue, ^{
            NSLog(@"Read finished.");
        });
    

    结果


    concurrent.png

    或者使用dispatch_group_wait

    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group = dispatch_group_create();
        dispatch_group_async(group, concurrentQueue, ^{
            for (int i = 0; i < 10000; i++) {
                NSLog(@"%@",array[i]);
            }
        });
        dispatch_group_async(group, concurrentQueue, ^{
            for (int i = 10000; i < 20000; i++) {
                NSLog(@"%@",array[i]);
            }
        });
        dispatch_group_async(group, concurrentQueue, ^{
            for (int i = 20000; i < 30000; i++) {
                NSLog(@"%@",array[i]);
            }
        });
    
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        NSLog(@"Read finished");
    

    dispatch_group_wait有两个参数,第一个是指定group,第二个表示如果group里的任务没有执行完成,要等待多久?DISPATCH_TIME_FOREVER就是表示:如果group中的任务没有执行完成,就一直等待。

    4. dispatch_barrier_async·

    • 对同个数据读取可以多个并行执行;
    • 对同个数据进行多个写入操作是不能并行执行的,因为我们无法确定并行执行的顺序;
    • 对同个数据进行读取和写入是不能并行执行的,这样会导致数据出错

    为了避免数据错乱,且要高效地完成操作,我们可以采用dispatch_barrier_async
    需求:可变数组array中有0-299共300个数据,我们需要读取最后三条数据,并且插入300-399后,再读取一次最后三条数据

    1. 如果不用dispatch_barrier_async
    NSMutableArray *array = [NSMutableArray array];
        for (int i = 0; i < 300; i ++) {
            [array addObject:@(i)];
        }
        dispatch_queue_t queue = dispatch_queue_create("com.testQueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 1] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 2] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 3] intValue]);
        });
    
        //写入操作
        dispatch_async(queue, ^{
            NSLog(@"---------Begin write----------");
            for (int i = 300; i < 400; i ++) {
                [array addObject:@(i)];
            }
        });
        
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 1] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 2] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 3] intValue]);
        });
    

    结果

    2019-05-15 09:55:43.535947+0800 GCD[2571:121141] 299
    2019-05-15 09:55:43.535949+0800 GCD[2571:121140] 298
    2019-05-15 09:55:43.535973+0800 GCD[2571:121138] 297
    2019-05-15 09:55:43.535999+0800 GCD[2571:121139] ---------Begin write----------
    2019-05-15 09:55:43.536086+0800 GCD[2571:121141] 299
    2019-05-15 09:55:43.536087+0800 GCD[2571:121140] 298
    2019-05-15 09:55:43.536132+0800 GCD[2571:121138] 299
    

    开始插入数据后,读取到的数据是乱序的,显然不是我们想要的效果

    1. 使用dispatch_barrier_async
    NSMutableArray *array = [NSMutableArray array];
        for (int i = 0; i < 300; i ++) {
            [array addObject:@(i)];
        }
        dispatch_queue_t queue = dispatch_queue_create("com.testQueue", DISPATCH_QUEUE_CONCURRENT);
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 1] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 2] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 3] intValue]);
        });
        
        //上面的读取操作可以并行执行,但是写入操作必须要单独执行
        dispatch_barrier_async(queue, ^{
            NSLog(@"---------Begin write----------");
            for (int i = 300; i < 400; i ++) {
                [array addObject:@(i)];
            }
        });
        
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 1] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 2] intValue]);
        });
        dispatch_async(queue, ^{
            NSLog(@"%d", [array[array.count - 3] intValue]);
        });
    

    结果

    2019-05-15 09:53:12.712380+0800 GCD[2495:115079] 299
    2019-05-15 09:53:12.712393+0800 GCD[2495:115077] 298
    2019-05-15 09:53:12.712408+0800 GCD[2495:115078] 297
    2019-05-15 09:53:12.712537+0800 GCD[2495:115078] ---------Begin write----------
    2019-05-15 09:53:12.712618+0800 GCD[2495:115078] 399
    2019-05-15 09:53:12.712629+0800 GCD[2495:115079] 398
    2019-05-15 09:53:12.712636+0800 GCD[2495:115077] 397
    

    是我们想要的效果
    我这里的读取都比较简单,假设需要大量的读取操作,依然可以按照这样的思路设计。

    相关文章

      网友评论

          本文标题:GCD1

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