关于GCD使用的一些函数

同步

所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。

同步代码如下:

dispatch_queue_tconcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);dispatch_sync(concurrentQueue, ^(){NSLog(@"A");});dispatch_sync(concurrentQueue, ^(){NSLog(@"B");});// 先输出 A 后输出 B 。

异步

异步的概念和同步相对。当一个异步过程调用发出后,调用者立刻得到结果就执行下面的功能。

异步代码如下:

dispatch_queue_tconcurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);dispatch_async(concurrentQueue, ^(){NSLog(@"A");});dispatch_async(concurrentQueue, ^(){NSLog(@"B");});// 可能先输出 A 后输出 B ,也可能先输出 B 后输出 A。因为异步下是没执行完就执行下面的功能

并行与并发区别

当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状态.这种方式我们称之为并发(Concurrent).

当系统有一个以上 CPU 时,则线程的操作有可能非并发.当一个 CPU 执行一个线程时,另一个CPU 可以执行另一个线程,两个线程互不抢占 CPU 资源,可以同时进行,这种方式我们称之为并行(Parallel)

分配队列

串行队列(一个队列一个队列的执行):

主队列。最常见的串行队列。使用dispatch_get_main_queue()获得。

自己创建的串行队列。

dispatch_queue_tserialQueue = dispatch_queue_create("me.iYiming.serialQueue", DISPATCH_QUEUE_SERIAL);

或者

dispatch_queue_tserialQueue = dispatch_queue_create("me.iYiming.serialQueue",NULL);

并发队列(几个队列“同时”执行):

系统队列

#defineDISPATCH_QUEUE_PRIORITY_HIGH2// 高#defineDISPATCH_QUEUE_PRIORITY_DEFAULT0// 默认#defineDISPATCH_QUEUE_PRIORITY_LOW (-2)// 低#defineDISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN//最低

dispatch_queue_tconcurrentQueue = dispatch_get_global_queue(XXXX,0);// 并发队列  XXXX 表示 上面的四个参数,

自己创建的并发队列

dispatch_queue_tconcurrentQueue = dispatch_queue_create("me.iYiming.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);

补充:

dispatch_set_target_queue()用法:

设置自己创建队列的目标队列,使创建的队列优先级和目标队列一样。

http://blog.csdn.net/growinggiant/article/details/41077221

上文中说了种情况:

一般都是把一个任务放到一个串行的queue中,如果这个任务被拆分了,被放置到多个串行的 queue 中,但实际还是需要这个任务同步执行,那么就会有问题,因为多个串行 queue 之间是并行的。

那该如何是好呢?

这是就可以使用dispatch_set_target_queue了。

如果将多个串行的 queue 使用dispatch_set_target_queue指定到了同一目标,那么着多个串行 queue 在目标 queue 上就是同步执行的,不再是并行执行。

除了上面链接中说到的用处外(也可以用别的方式替代),感觉没多大用处?!

分配组

关于使用分配组,我用到的情况就是这个情形下:执行 A 任务,B任务后(A B 可以同时做),最后再做 C 任务。

dispatch_queue_t concurrentQueue = dispatch_queue_create("me.iYiming.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_group_t group = dispatch_group_create();dispatch_group_async(group, concurrentQueue, ^{  // A 任务});dispatch_group_async(group, concurrentQueue, ^{  // B 任务});dispatch_group_notify(group, concurrentQueue, ^{  // C 任务});

分配屏障

我们使用分配屏障会等当前队列执行处理全部结束后,再将指定的处理追加到该队列上,然后再由分配屏障追加 的处理执行完毕后,当前队列才恢复为一般的动作,追加到该队列的处理又开始执行。

代码如下

dispatch_queue_t myQueue = dispatch_get_global_queue(0,0);dispatch_async(myQueue, ^{  NSLog(@"123");});dispatch_async(myQueue, ^{  NSLog(@"456");});dispatch_barrier_async(myQueue, ^{  NSLog(@"789");});dispatch_async(myQueue, ^{  NSLog(@"10");});

举个例子

我们都会对数据进行读写操作,为了防止多个线程对数据进行安全访问。我们需要使用锁来实现某种同步机制。

在 GCD 出现之前,有两种办法:

采用内置的“同步块”

- (void) synchronizationMethod{@synchronized(self) {// 使用同步块}  }

直接使用 NSLock 对象(也可以使用 NSRecursiveLock 这种递归锁)。

_lock = [[NSLockalloc] init];  - (void) synchronizationMethod{      [_lock lock];//NSLock 对象方式[_lock unlock];  }

互斥锁分为 递归锁 和 非递归锁。

同一个线程可以多次获取同一个递归锁,不会产生死锁。

如果一个线程多次获取同一个非递归锁,则会产生死锁。

这两种方法都很好,不过也有其缺陷。比方说:

在极端情况下,同步块会导致死锁,另外,其效率也不见得高.

滥用@sychronized(self)会很危险,因为所有同步块都会彼此抢夺同一个锁。要是有很多歌属性都这么写的话,那么每个属性的同步块都要等其他所有同步块执行完毕才能执行,这也许不是我们想要的结果。

我们可以使用 “串行同步队列”,将读取操作及写入操作都安排在同一个队列里,即可保证数据同步。

_serialQueue = dispatch_queue_create("me.iYiming.serialQueue", DISPATCH_QUEUE_SERIAL);- (NSString*) someString{    __blockNSString*localSomeString;    __weaktypeof(self) wakeSelf =self;dispatch_sync(_serialQueue, ^{        localSomeString = wakeSelf.someString;    });returnlocalSomeString;}- (void) setSomeString:(NSString*)someString{    __weaktypeof(self) wakeSelf =self;dispatch_sync(_serialQueue, ^{        wakeSelf.someString= someString;    });}

还可以进一步优化。设置方法并不一定非得是同步的。设置实例变量所用的块,并不需要向设置返回什么值。也就是可以修改成如下:

- (void) setSomeString:(NSString*)someString{    __weaktypeof(self) wakeSelf =self;dispatch_async(_serialQueue, ^{        wakeSelf.someString= someString;    });}

但经过测试一下程序性能,那么可能会发现这种写法比原来慢,因为执行异步派发时,需要拷贝块。若拷贝所用的时间明显超过执行块所花的时间,则这种做法将比原来更慢。

多个获取方法可以并发执行,而获取方法与设置方法之间不能并发执行,利用这个特点,还能写出更快一些的代码来。

_concurrentQueue = dispatch_queue_create("me.iYiming.concurrentQueue", DISPATCH_QUEUE_CONCURRENT);- (NSString*) someString{    __blockNSString*localSomeString;    __weaktypeof(self) wakeSelf =self;dispatch_sync(_concurrentQueue, ^{        localSomeString = wakeSelf.someString;    });returnlocalSomeString;}- (void) setSomeString:(NSString*)someString{    __weaktypeof(self) wakeSelf =self;    dispatch_barrier_sync(_concurrentQueue, ^{// 同步屏障wakeSelf.someString= someString;    });}


GCD VS NSOperation


GCD 的优点:

1. GCD 提供的dispatch_after支持调度下一个操作的开始时间而不是直接进入睡眠。

2. NSOperation 中没有类似dispatch_source_t,dispatch_io,dispatch_data_t,dispatch_semaphore_t等操作。


NSOperation 的优点:

1. GCD 没有操作依赖。我们可以让一个 Operation 依赖于另一个 Operation,这样的话尽管两个 Operation 处于同一个并行队列中,但前者会直到后者执行完毕后再执行;

2. GCD 没有操作优先级(GCD 有队列优先级),能够使同一个并行队列中的任务区分先后地执行,而在 GCD 中,我们只能区分不同任务队列的优先级,如果要区分block任务的优先级,也需要大量的复杂代码;

3. GCD 没有 KVO。NSOperation 可以监听一个 Operation 是否完成或取消,这样能比GCD 更加有效地掌控我们执行的后台任务

4. 在NSOperationQueue 中,我们可以随时取消已经设定要准备执行的任务(当然,已经开始的任务就无法阻止了),而 GCD 没法停止已经加入 queue 的 Block(其实是有的,但需要许多复杂的代码)

5. 我们能够对 NSOperation 进行继承,在这之上添加成员变量与成员方法,提高整个代码的复用度,这比简单地将 block 任务排入执行队列更有自由度,能够在其之上添加更多自定制的功能。

使用dispatch_once创建单例

直接上代码:

//保存单例对象的静态全局变量staticid_instance;  + (instancetype)sharedTools {return[[selfalloc]init];  }//在调用alloc方法之后,最终会调用allocWithZone方法+ (instancetype)allocWithZone:(struct_NSZone*)zone {//保证分配内存的代码只执行一次staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{          _instance = [superallocWithZone:zone];      });return_instance;  }//这是个对象方法,既然有对象而且是单例,那么调用者就是这个单例对象了,那就返回调用的对象就行- (id)copyWithZone:(NSZone*)zone {returnself;  }//这是个对象方法,既然有对象而且是单例,那么调用者就是这个单例对象了,那就返回调用的对象就行- (id)mutableCopyWithZone:(NSZone*)zone {returnself;  }#if __has_feature(objc_arc)

//如果是ARC环境#else//如果不是ARC环境//既然是单例对象,总不能被人给销毁了吧,一旦销毁了,分配内存的代码已经执行过了,就再也不能创建对象了。所以覆盖掉release操作- (onewayvoid)release {  }//这是个对象方法,既然有对象而且是单例,那么调用者就是这个单例对象了,那就返回调用的对象就行- (instancetype)retain {returnself;  }//为了便于识别,这里返回 MAXFLOAT ,别的程序员看到这个数据,就能意识到这是单例了。纯属装逼……- (NSUInteger)retainCount {returnMAXFLOAT;  }#endif

原文链接:http://www.jianshu.com/p/6a0fd59e8d2f

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容