《Objective-C高级编程》(三)GCD

一、多线程

1、一个CPU执行的CPU命令列为一条无分叉路径即为线程。
2、多线程可保证应用程序的响应性能。
2、多线程易发生问题,如数据竞争、死锁、线程过多消耗大量内存等

二、GCD

GCD是异步执行任务的技术之一。
GCD能生成必要的线程并执行任务。
GCD系统级线程管理提高执行效率。

三、GCD API

1、dispatch_sync

// Submits a block for synchronous execution on a dispatch queue.
// Submits a workitem to a dispatch queue like dispatch_async(), however dispatch_sync() will not return until the workitem has finished.
// Calls to dispatch_sync() targeting the current queue will result in dead-lock.
// Use of dispatch_async() is preferred.
// Unlike dispatch_async(), no retain is performed on the target queue.
void dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);

1、dispatch_sync容易引起死锁,推荐使用dispatch_async
2、dispatch_sync在指定的处理执行结束之前,该函数不会返回。
3、dispatch_sync不具备开启新线程的能力。

// 死锁(Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0))
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_sync(mainQueue, ^{
    NSLog(@"Thread:%@", [NSThread currentThread]);
});

dispatch_queue_t serialQueue = dispatch_queue_create("com.jd.queue.serial", DISPATCH_QUEUE_SERIAL);
dispatch_sync(serialQueue, ^{
    for (NSInteger i = 0; i < 10000; i++) {
        // 自行创建的串行队列,依然是在主线程中执行,dispatch_sync不具备开启新线程的能力
        NSLog(@"Thread:%@ - %ld", [NSThread currentThread], (long)i);
    }
});
// 提交到串行队列的任务全部执行完之后才会返回并继续执行
NSLog(@"Thread:%@ - Log Finish", [NSThread currentThread]);

2、dispatch_async

// Submits a block for asynchronous execution on a dispatch queue.
// Calls to dispatch_async() always return immediately after the block has been submitted, and never wait for the block to be invoked.
// The target queue determines whether the block will be invoked serially or concurrently with respect to other blocks submitted to that same queue.
// The system will hold a reference on the target queue until the block has finished.
// The block to submit to the target dispatch queue. This function performs Block_copy() and Block_release() on behalf of callers.
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

1、dispatch_async调用后立刻返回,不等待任务执行
2、dispatch_async的目标队列决定任务串行或者并行执行
3、dispatch_async具备开启新线程的能力

dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_async(mainQueue, ^{
    for (NSInteger i = 0; i < 10000; i++) {
        // 任务串行或者并行,取决于队列类型
        NSLog(@"Thread:%@ - %ld", [NSThread currentThread], (long)i);
    }
 });    
// 提交任务后立即返回,继续执行后续逻辑,不等待任务执行
NSLog(@"Thread:%@ - Log Finish", [NSThread currentThread]);

3、dispatch_get_main_queue

// Returns the default queue that is bound to the main thread.
// The main queue is meant to be used in application context to interact with the main thread and the main runloop.
dispatch_queue_main_t dispatch_get_main_queue(void)

1、Main Dispatch Queue是在主线程中执行的Serial Dispatch Queue

// Returns a well-known global concurrent queue of a given quality of service class.
dispatch_queue_global_t dispatch_get_global_queue(long identifier, unsigned long flags);
// Creates a new dispatch queue to which blocks may be submitted.
// Dispatch queues created with the DISPATCH_QUEUE_SERIAL or a NULL attribute invoke blocks serially in FIFO order.
// Dispatch queues created with the DISPATCH_QUEUE_CONCURRENT attribute may invoke blocks concurrently (similarly to the global concurrent queues, but potentially with more overhead), and support barrier blocks submitted with the dispatch barrier API, which e.g. enables the implementation of efficient reader-writer schemes.
// When a dispatch queue is no longer needed, it should be released with dispatch_release(). Note that any pending blocks submitted asynchronously to a queue will hold a reference to that queue.
dispatch_queue_t dispatch_queue_create(const char *_Nullable label, dispatch_queue_attr_t _Nullable attr);

1、多个Serial Dispatch Queue可并行执行
2、避免多个线程数据竞争时使用Serial Dispatch Queue
3、Dispatch Queue必须由开发者负责释放操作,并没有像Block作为OC对象处理的技术。通过dispatch_queue_create函数生成的Dispatch Queue在使用结束后通过dispatch_release函数释放
4、Block通过dispatch_retain持有Dispatch Queue,Block执行结束,通过dispatch_release释放持有的Dispatch Queue。

// Schedule a block for execution on a given queue at a specified time.
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);

1、dispatch_after并不是在指定时间后执行处理,而是在指定时间追加到Dispatch Queue
2、dispatch_after不受RunLoop Mode切换的影响

// Creates new group with which blocks may be associated.
//  The group object memory is freed with dispatch_release().
dispatch_group_t dispatch_group_create(void);

1、通过dispatch_group_create函数生成的Dispatch Group在使用结束后通过dispatch_release函数释放

// Submits a block to a dispatch queue and associates the block with the given dispatch group.
// The dispatch group may be used to wait for the completion of the blocks it references.
void dispatch_group_async(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

1、与Dispatch Queue相同,Block通过dispatch_retain持有Dispatch Group,Block执行结束,通过dispatch_release释放持有的Dispatch Group。

// Schedule a block to be submitted to a queue when all the blocks associated with a group have completed.
void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);

1、相比dispatch_group_wait推荐使用dispatch_group_notify,可简化源代码

// Wait synchronously until all the blocks associated with a group have completed or until the specified timeout has elapsed.
// Returns zero on success (all blocks associated with the group completed within the specified timeout) or non-zero on error (i.e. timed out).
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

1、可设置超时

// Submits a barrier block for asynchronous execution on a dispatch queue.
// It enables the implementation of efficient reader/writer schemes.
// Barrier blocks only behave specially when submitted to queues created with the DISPATCH_QUEUE_CONCURRENT attribute; 
// A barrier block will not run until all blocks submitted to the queue earlier have completed, and any blocks submitted to the queue after a barrier block will not run until the barrier block has completed.
// When submitted to a a global queue or to a queue not created with the DISPATCH_QUEUE_CONCURRENT attribute, barrier blocks behave identically to blocks submitted with the dispatch_async()/dispatch_sync() API.
void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

1、使用Serial Dispatch Queue可避免数据竞争
2、使用Concurrent Dispatch Queue和dispatch_barrier_async可实现高效率的数据库访问和文件访问

// Submits a block to a dispatch queue for parallel invocation.
// This function waits for the task block to complete before returning.
// If the specified queue is concurrent, the block may be invoked concurrently, and it must therefore be reentrant safe.
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

1、dispatch_apply会等待处理执行结束,因此推荐在dispatch_async中非同步地执行dispatch_apply

// Suspends the invocation of blocks on a dispatch object.
// A suspended object will not invoke any blocks associated with it. The suspension of an object will occur after any running block associated with the object completes.
void dispatch_suspend(dispatch_object_t object);
// Resumes the invocation of blocks on a dispatch object.
void dispatch_resume(dispatch_object_t object);

1、dispatch_suspenddispatch_resume对已经执行的处理没有什么影响。挂起后,追加到Dispatch Queue中但尚未执行的处理停止执行。

// Execute a block once and only once.
void dispatch_once(dispatch_once_t *predicate, DISPATCH_NOESCAPE dispatch_block_t block);

1、使用dispatch_once,在多线程环境下执行,也可保证安全,常用于生成单例

// Creates new counting semaphore with an initial value.
dispatch_semaphore_t dispatch_semaphore_create(long value);

1、与Dispatch Queue和Dispatch Group相同,通过dispatch_release释放

// Wait (decrement) for a semaphore.
// Decrement the counting semaphore. If the resulting value is less than zero, this function waits for a signal to occur before returning.
long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);

1、等待semaphore大于等于1,对该计数-1并返回。
2、返回值为0为信号量满足条件,非0为达到超时时间。

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

推荐阅读更多精彩内容