iOS多线程编程之GCD

2015-12-02  本文已影响40人  华子小筑

文章资料来源《Objective-C高级编程》之GCD

GCD是一种异步执行任务的技术,对于编程层面上异步执行就意味着创建一个线程(操作系统能夠進行運算调度的最小單位,是进程中一个单一顺序的控制流--from wiki)去执行Task;GCD提供了两种队列和相关API使得开发者只需要关心该选择哪种队列去执行任务即可;

GCD的队列

dispatch_queue_create 创建队列

serial queue

  /*
 1>serial Queue:系统默认创建一个线程,队列中的任务是顺序执行
 2>创建多个serial queue 的执行是并发的没有顺序
 3>解决数据竞争问题:可以将任务放在serial queue中 保证任务按照顺序执行就能解决数据竞争
*/
dispatch_queue_t mySerialQueue = dispatch_queue_create("com.hua.example.serialQueue", DISPATCH_QUEUE_SERIAL);

concurrent queue

 /*
  1 concurrent queue 添加到队列中的任务会并发执行,没有顺序性
 */
dispatch_queue_t myConcurrentQueue=dispatch_queue_create("com.hua.example.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

非ARC下生成的队列还必须使用dispatch_release(Queue);来释放指定的队列

Main Dispatch Queue and Global Dispatch Queue

Main Dispatch Queue

  /*
  dispatch_get_main_queue
 (1)main queue 是一中serial queue,task是放在主线程的Runloop中执行的;
 (2)一些UI的更新操作需要放在主线程中,使用main queue是比较简单的
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();

global Dispatch Queue

 /*
   dispatch_get_global_queue
 (1)global queue 是一种concurrent queue,可以通过设置queue的priority指定执行的优先级;
 */
dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);  

dispatch_set_target_queue

 /*
 dispatch_set_target_queue的第一个参数是指定要变更优先级的队列;指定与要使用优先级相同优先级的队列为第二个参数
 */
dispatch_queue_t serialqueue1 = dispatch_queue_create("serialqueue1", NULL);
dispatch_queue_t serialqueue2 = dispatch_queue_create("serialqueue2", NULL);
dispatch_set_target_queue(serialqueue2, serialqueue1);
/*  

dispatch_after

/*
  延迟若干时间处理某一个Task,只是追加task到某一个队列,并不一定立即执行task
*/
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
    NSLog(@"wait at least three seconds!!");
});

dispatch Group

dispatch group 的出现可以解决多个并发task执行后能收到通知再执行其他任务操作的需求;

  /*
  1; 如果使用 serial queue 所有的task执行完毕后在执行done task
  2:如果使用 concurrent queue 所有的task执行后没办法 执行行done task 就需要 dispatch_group
 */
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, ^{
    NSLog(@"blok1");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok2");
});
dispatch_group_async(group, queue, ^{
    NSLog(@"blok3");
});
dispatch_group_async(group, queue, ^{
    [NSThread sleepForTimeInterval:2.0];
    NSLog(@"blok4");
});
// 监听group 中的task 是否已经全部执行完成
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"done!!");
});
//   dispatch_group_wait会hold住当前线程直到所有task执行完毕
//    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

NSLog(@"all finish!!!!");

多个网络请求执行操作完成在执行下一步操作的需求如何实现?

 // 多个网络请求完成后再做新的任务
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //网络请求操作1
        dispatch_group_leave(group);
    });
    dispatch_group_enter(group);
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //网络请求操作2
        dispatch_group_leave(group);
    });

dispatch_barrier_async

多线程操作产生的一个问题就是数据资源的竞争,读写操作如何能保证线程安全性;dispatch_barrier_async提供了解决方案

 /*
   使用concurrent dispatch queue 和 dispatch barrier async 函数可实现高效率的数据库访问和文件读取
 */
dispatch_queue_t queue = dispatch_queue_create("test.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
    NSLog(@"task1forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task2forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task3forReading!");
});
dispatch_barrier_async(queue, ^{
    // 此taskforWriting 会等到加入concurrentQueue中的task执行完毕后,执行taskforWriting,等到该taskforWriting执行完毕后在执行 concurrentQueue中的task
    NSLog(@"taskforWriting!");
});
dispatch_async(queue, ^{
    NSLog(@"task4forReading!");
});
dispatch_async(queue, ^{
    NSLog(@"task5forReading!");
});

dispatch_sync

/*
dispatch_sync 函数意味着等待;它要等待task执行完毕后再做返回
*/
//使用dispatch_sync 容易造成死锁
//在主线程中执行以下源代码会造成死锁
/*
  main_queue 是一个serialQueue ,使用dispatch_sync将task加入到mainqueue中task会等待mainqueue中的任务执行完成,而mainqueue又要等待task完成,由此造成了死锁;
 */
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_sync(main_queue, ^{
    NSLog(@"hello dispatch_sync!");
});
//>2在主线程中执行以下源代码也会造成死锁
dispatch_async(main_queue, ^{
   dispatch_sync(main_queue, ^{
       NSLog(@"hello!!");
   });
});

dispatch_apply

  NSMutableArray* tempArr  = [@[@"key1",@"key2",@"key3",@"key4",@"key5"] mutableCopy];
   // 1 按照指定的次数将指定的Block追加到指定的Dispatch_Queue中,并等待全部处理执行结束
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_apply([tempArr count], queue, ^(size_t index) {
        // 要做数据更新操作
        NSLog(@"%d",index);
    });
    NSLog(@"task done");
    /*
     1 对数组进行循环遍历的方法
       1》 for循环
       2》 block
       3》 dispatch_apply
      2 dispatch_apply 要等待结束,最好和 dispatch_async函数混合使用
     */

挂起队列和执行队列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//挂起队列
dispatch_suspend(queue);
//恢复指定队列
dispatch_resume(queue);  

dispatch_Semaphore

 // 1  向数组中增加对象由于内存错误导致异常的概率会很高
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray* mutable_arr =[NSMutableArray array];
for(int i = 0;i<100000;++i)
{
   dispatch_async(queue, ^{
       [mutable_arr addObject:[NSNumber numberWithInt:i]];
   });
}


// 2 使用dispatch_semaphore进行更细粒度的线程管理
dispatch_queue_t global_queue = dispatch_queue_create(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*
  生成Dispatch Semahpore
  dispatch_Semahpore 的计数初始值设定为“1”
  这样能保证访问NSMutableArray类对象的线程,同时只有1个
 */
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
NSMutableArray* array =[NSMutableArray array];
for(int i = 0;i<10000;i++)
{
    dispatch_async(global_queue, ^{
        /*
         等待Dispatch Semaphore
         直到Dispatch Semphore的计数值达到大于等于1;
         */
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        /*
         由于dispatch Semaphore 的计数值达到大于等于1
         所以将Dispatch semaphore 的计数值减去1
         dispatch_semaphore_wait 函数执行返回
         执行到此 dispatch Semaphore的计数值恒为“0”
         */
        
        [array addObject:[NSNumber numberWithInt:i]];
        
        /*
         排他控制处理结束,所以通过dispatch_semaphore_signal函数 将
         Dispatch Semaphore的计数值加1
         如果有通过dispatch_semaphore_wait 函数 等待dispatch Semaphore 的计数值增加的线程 就由最先等待的线程执行
         */
        dispatch_semaphore_signal(semaphore);

    });
}

dispatch_once

保证应用程序中只执行一次指定处理的API

 +(instancetype)shareInstance
    {
        static ViewController* _vc;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _vc =[[self alloc] init];
        });
        return _vc;
    }
上一篇下一篇

猜你喜欢

热点阅读