变更记录

序号 录入时间 录入人 备注
1 2016-03-22 Alfred Jiang -
1 2016-11-16 Alfred Jiang -

方案名称

专题 - GCD 介绍与使用(二)

关键字

专题 \ Block \ Dispatch \ GCD \ 异步 \ 并行

需求场景

  1. 熟悉 Objective-C GCD

参考链接

  1. GitHub - nixzhu/dev-blog - GCD 深入理解:第一部分
  2. GitHub - nixzhu/dev-blog - GCD 深入理解:第二部分
  3. Ray Wenderlich - Grand Central Dispatch In-Depth: Part 1/2
  4. Ray Wenderlich - Grand Central Dispatch In-Depth: Part 2/2
  5. 伯乐在线 - GCD那些事(推荐)

详细内容

以下内容整理自 伯乐在线 - GCD那些事 原文出处 : 像晨宇(@向晨宇_)

第一组 API : 信号量相关

  • dispatch_semaphore_t
  • dispatch_semaphore_wait
  • dispatch_semaphore_signal

作用 : 在多线程下控制多线程的并发数目

  • 创建信号量,可以设置信号量的资源数。0 表示没有资源,调用 dispatch_semaphore_wait 会立即等待 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  • 等待信号,可以设置超时参数。该函数返回 0 表示得到通知,非 0 表示超时 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  • 通知信号,如果等待线程被唤醒则返回非 0 ,否则返回 0 dispatch_semaphore_signal(semaphore);
使用场景一 :并发队列

每执行完 10 个任务后,休息两秒,再继续执行 10 个任务

-(void) testSemaphore{

    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(10); //信号总量是 10
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    for (int i = 0; i 100; i++)
    {
       dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);//信号量 -1
       dispatch_group_async(group, queue, ^{
           NSLog(@"%i",i);
           sleep(2);
           dispatch_semaphore_signal(semaphore);   //信号量 +1
       });
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
}

执行结果

2016-06-01 20:30:35.113 XXGCD[39559:306278] 7
2016-06-01 20:30:35.113 XXGCD[39559:306277] 6
2016-06-01 20:30:35.113 XXGCD[39559:306271] 0
2016-06-01 20:30:35.113 XXGCD[39559:306274] 3
2016-06-01 20:30:35.113 XXGCD[39559:306270] 1
2016-06-01 20:30:35.113 XXGCD[39559:306272] 2
2016-06-01 20:30:35.113 XXGCD[39559:306275] 4
2016-06-01 20:30:35.113 XXGCD[39559:306276] 5
2016-06-01 20:30:35.113 XXGCD[39559:306279] 8
2016-06-01 20:30:35.113 XXGCD[39559:306280] 9

2016-06-01 20:30:37.117 XXGCD[39559:306272] 11
2016-06-01 20:30:37.117 XXGCD[39559:306270] 12
2016-06-01 20:30:37.117 XXGCD[39559:306275] 10
2016-06-01 20:30:37.117 XXGCD[39559:306280] 13
2016-06-01 20:30:37.117 XXGCD[39559:306276] 15
2016-06-01 20:30:37.117 XXGCD[39559:306279] 14
2016-06-01 20:30:37.117 XXGCD[39559:306274] 16
2016-06-01 20:30:37.117 XXGCD[39559:306277] 17
2016-06-01 20:30:37.117 XXGCD[39559:306278] 18
2016-06-01 20:30:37.117 XXGCD[39559:306271] 19
使用场景二 :等待异步线程完成
-(void) testAsynFinished{

    __block BOOL isok = NO;
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    XXEngine *engine = [[XXEngine alloc] init];

    [engine queryCompletion:^(BOOL isOpen) { // sleep 了 3 秒
                        isok = isOpen;
                        dispatch_semaphore_signal(sema);
                        NSLog(@"success!");
                    }
                    onError:^(BOOL isOpen, int errorCode) {
                        isok = NO;
                        dispatch_semaphore_signal(sema);
                        NSLog(@"error!");
                    }];

    NSLog(@"finished");
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
}

执行结果

2016-06-02 15:01:06.168 XXGCD[35443:290673] success!
2016-06-02 15:01:06.168 XXGCD[35443:290673] finished
使用场景三 :生产者,消费者
-(void) testProductAndConsumer{

    dispatch_semaphore_t sem = dispatch_semaphore_create(0);

    dispatch_queue_t producerQueue = dispatch_queue_create("producer", DISPATCH_QUEUE_CONCURRENT);//生产者线程跑的队列
    dispatch_queue_t consumerQueue = dispatch_queue_create("consumer", DISPATCH_QUEUE_CONCURRENT);//消费者线程跑的队列

    __block int cakeNumber = 0;
    dispatch_async(producerQueue,  ^{ //生产者队列
        while (1) {
            if (!dispatch_semaphore_signal(sem))
            {
                NSLog(@"Product:生产出了第%d个蛋糕",++cakeNumber);
                sleep(1); //wait for a while
                continue;
            }
        }
    });
    dispatch_async(consumerQueue,  ^{//消费者队列
        while (1) {
            if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 0*NSEC_PER_SEC))){
                if(cakeNumber > 0){
                    NSLog(@"Consumer:拿到了第%d个蛋糕",cakeNumber--);
                }
                continue;
            }
        }
    });
}

执行结果

2016-06-02 15:04:18.785 XXGCD[35593:294211] Product:生产出了第1个蛋糕
2016-06-02 15:04:18.785 XXGCD[35593:294209] Consumer:拿到了第1个蛋糕
2016-06-02 15:04:19.790 XXGCD[35593:294209] Consumer:拿到了第1个蛋糕
2016-06-02 15:04:19.790 XXGCD[35593:294211] Product:生产出了第1个蛋糕

第二组 API : Group 相关

  • dispatch_group_t
  • dispatch_group_notify

作用 : 用来阻塞一个线程,直到一个或多个任务完成执行

使用场景一 :并发队列
-(void) testGCDGroup{

    dispatch_group_t group = dispatch_group_create();
    for(int i = 0; i 10; i++)
    {
        dispatch_group_enter(group);
        [[XXEngine instance] doAsyncWorkWithCompletionBlock:^{
            dispatch_group_leave(group);
        }];
    }

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    NSLog(@"testGCDGroup1 更新UI操作");
}

等价于

-(void) testGCDGroup2{

    dispatch_group_t group = dispatch_group_create();
    for(int i = 0; i 10; i++)
    {
        dispatch_group_enter(group);
        [[XXEngine instance] doAsyncWorkWithCompletionBlock:^{
            dispatch_group_leave(group);
        }];
    }

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"testGCDGroup2 更新UI操作");
    });
}

执行结果

2016-06-02 15:29:54.392 XXGCD[36197:313551] test
2016-06-02 15:29:54.392 XXGCD[36197:313569] test
2016-06-02 15:29:54.393 XXGCD[36197:313572] test
2016-06-02 15:29:54.393 XXGCD[36197:313571] test
2016-06-02 15:29:54.392 XXGCD[36197:313558] test
2016-06-02 15:29:54.392 XXGCD[36197:313568] test
2016-06-02 15:29:54.392 XXGCD[36197:313563] test
2016-06-02 15:29:54.393 XXGCD[36197:313570] test
2016-06-02 15:29:54.393 XXGCD[36197:313573] test
2016-06-02 15:29:54.393 XXGCD[36197:313574] test
2016-06-02 15:29:56.398 XXGCD[36197:313513] testGCDGroup1 更新UI操作
使用场景二 :等待异步线程完成
-(void) testGCDGroup3{

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_group_t group = dispatch_group_create();

    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:1];
        NSLog(@"group1");
    });

    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:2];
        NSLog(@"group2");
    });

    dispatch_group_async(group, queue, ^{
        [NSThread sleepForTimeInterval:3];
        NSLog(@"group3");
    });

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"testGCDGroup3 更新UI操作");
    });
}

执行结果

2016-06-02 15:58:29.041 XXGCD[36675:337871] group1
2016-06-02 15:58:30.041 XXGCD[36675:337880] group2
2016-06-02 15:58:31.043 XXGCD[36675:337884] group3
2016-06-02 15:58:31.043 XXGCD[36675:337834] testGCDGroup3 更新UI操作

第三组 API : 同步函数

  • dispatch_apply

会阻塞当前线程直到所有循环迭代执行完成。当提交到并发 queue 时,循环迭代的执行顺序是不确定的

使用场景一 :并发队列

static int i = 0;

-(void) testGCDApply{

    dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply(10, globalQ, ^(size_t index) {
        // 执行10次
        [self printTest];
    });
}

-(void) printTest{

    NSLog(@"%d",++i);
}

执行结果

2016-06-02 16:06:50.799 XXGCD[37133:347348] 6
2016-06-02 16:06:50.799 XXGCD[37133:347329] 2
2016-06-02 16:06:50.799 XXGCD[37133:347346] 8
2016-06-02 16:06:50.799 XXGCD[37133:347336] 1
2016-06-02 16:06:50.799 XXGCD[37133:347340] 3
2016-06-02 16:06:50.799 XXGCD[37133:347296] 4
2016-06-02 16:06:50.799 XXGCD[37133:347347] 7
2016-06-02 16:06:50.799 XXGCD[37133:347349] 5
2016-06-02 16:06:50.799 XXGCD[37133:347329] 9
2016-06-02 16:06:50.799 XXGCD[37133:347348] 10

第四组 API : 时间相关

  • dispatch_source_set_timer
  • dispatch_suspend
  • dispatch_resume
  • dispatch_source_cancel

dispatch_suspend:暂停dispatch_source_t dispatch_resume:恢复dispatch_source_t dispatch_cancel:取消dispatch_source_t

使用场景一 : 实现 NSTimer 相关功能
@interface XXGCDTimer()
{
    dispatch_source_t _timer;
}
@end

@implementation XXGCDTimer

-(void) startGCDTimer{

    NSTimeInterval period = 1.0; //设置时间间隔
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), period * NSEC_PER_SEC, 0); //每秒执行
    dispatch_source_set_event_handler(_timer, ^{
        //在这里执行事件
        NSLog(@"每秒执行test");
    });

    dispatch_resume(_timer);
}

-(void) pauseTimer{

    if(_timer){

        dispatch_suspend(_timer);
    }
}

-(void) resumeTimer{

    if(_timer){

        dispatch_resume(_timer);
    }
}

-(void) stopTimer{

    if(_timer){

        dispatch_source_cancel(_timer);
        _timer = nil;
    }
}
@end

更多 API 及使用场景见参考链接

  • dispatch_barrier_async
  • dispatch_sync 和 dispatch_async
  • dispatch_get_global_queue
  • dispatch_once
  • dispatch_after

效果图

(无)

备注

results matching ""

    No results matching ""