多线程编程GCD

2018-03-30  本文已影响21人  绍清_shao

1. 什么是GCD

异步执行任务的技术之一
在GCD之前,cocoa框架提供了NSObject类performSelectorInBackground:withObject实例方法和performSelectorOnMainThread实例方法

2. 什么是dispatch_sync和dispatch_async

dispatch_sync函数的“sync”意味着“非同步”,就是将指定的Block“非同步”追加到Dispatch Queue中。dispatch_sync函数不做任何等待。

dispatch_async函数的“async”意味着“同步”,就是将指定的Block“同步”追加到Dispatch Queue中。在追加Block结束之前,dispatch_sync函数会一直等待。等待意味着执行此Block的线程停止了。

3. 什么是Dispatch Queue

执行处理时存在两种Dispatch Queue,

4. 如何创建Dispatch Queue

  1. 第一种方法是通过GCD的API生成Dispatch Queue
    dispatch_queue_create(<#const char * _Nullable label#>, <#dispatch_queue_attr_t _Nullable attr#>)
    第一个参数指定Queue名称
    推荐使用应用程序ID这种逆序全程域名。该名称在Xcode和Instrument的调试器中作为Dispatch Queue名称表示,也会出现在应用程序崩溃时所生成的CrashLog中
    第二个参数创建Dispatch Queue的类型
    如果指定为NULL,创建的是Serial Dispatch Queue。要生成Concurrent Dispatch Queue时要指定为DISPATCH_QUEUE_CONCURRENT

  2. 第二种方法是获取系统标准提供的Dispatch Queue
    Main Dispatch Queue
    正如其名称含有"Main"一样,是在主线程中执行的Dispatch Queue。因为主线程只有一个,所以Main Dispatch Queue自然就是Serial Dispatch Queue。
    Global Dispatch Queue
    所有应用程序都能使用的Concurrent Dispatch Queue,没有必要通过dispatch_queue_create函数逐个生成。
    另外Global Dispatch Queue有4个执行优先级,分别是高优先级(High Priority)、默认优先级(Default Priority)、低优先级(low Priority)、后台优先级(background Priority)。在向Global Dispatch Queue追加处理时,应选择与处理内容对应的执行优先级的Global Dispatch Queue。
    获取方法

    /*
     *  Main Dispatch Queue获取方法
     */
    dispatch_queue_t myConcurrentQueue =
    dispatch_get_main_queue();

    /*
     *  Global Dispatch Queue (高优先级) 的获取方法
     */
    dispatch_queue_t    globalDispatchQueueHige =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);

    /*
     *  Global Dispatch Queue (默认优先级) 的获取方法
     */
    dispatch_queue_t    globalDispatchQueueDefalut =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    /*
     *  Global Dispatch Queue (低优先级) 的获取方法
     */
    dispatch_queue_t    globalDispatchQueuelow =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    /*
     *  Global Dispatch Queue (后台优先级) 的获取方法
     */
    dispatch_queue_t    globalDispatchQueuebackground =
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

5. dispatch_after指定时间后执行处理

这里的时间可以是相对时间,例如3秒后执行,也可以是绝对时间,例如指定2100年11月11日11时这一绝对时间,可以作为粗略闹钟功能使用。
注意
dispatch_after函数并不是在指定时间后执行处理(block),而是指定时候后追加处理到Dispatch Queue中。如果线程本身有大量处理要追加,这个时间延长越厉害。
例子:

// 相对时间
  dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull * NSEC_PER_SEC);
  dispatch_after(time, dispatch_get_main_queue(), ^{
        NSLog(@"3 秒后 执行这个");
    });
// 绝对时间
//5秒后的时间,可以指定任意绝对时间,例子里只是简单指定比现在晚5秒。
    NSDate *furtureDate = [[NSDate alloc] initWithTimeIntervalSinceNow:5];
    dispatch_time_t relTime = getDispatchTimeByDate(furtureDate);
    dispatch_after(relTime, dispatch_get_main_queue(), ^{
        NSLog(@"5 秒后 执行这个");
    });

注意:dispatch_walltime函数由POSIX中使用的struct timespec类型
的时间得到dispatch_time_t类型的值。具体装换如下:

dispatch_time_t getDispatchTimeByDate(NSDate *date) {
    NSTimeInterval interval;
    double second, subsecond;
    struct timespec time;
    dispatch_time_t milestone;
    
    interval = [date timeIntervalSince1970];
    subsecond = modf(interval, &second);
    time.tv_sec = second;
    time.tv_nsec = subsecond * NSEC_PER_SEC;
    milestone = dispatch_walltime(&time, 0);
    
    return milestone;
}

dispatch_after(dispatch_time_t when, dispatch_queue_t _Nonnull queue, ^(void)block)
第一个参数是指定时间dispatch_time_t。该值使用dispatch_time函数或者dispatch_walltime生成。
第二个参数指定要追加的Dispatch Queue。
最后一个参数要执行处理的Block。

6. Dispatch Group

使用场景是在追加到Dispatch Queue中多个处理全部结束后想执行结束处理。

Dispatch Group

7. dispatch_barrier_queue

使用场景:文件的读取与写入,为了避免发生数据竞争,多个文件的读取操做可以并行执行,但不可以与文件的写入操作并行,文件的写入操作之间只能串行且不能有文件读取操作存在。dispatch_barrier_async函数可以实现高效率的数据库访问和文件访问

dispatch_barrier_queue
上一篇 下一篇

猜你喜欢

热点阅读