池州网站建设兼职,个人网站申请备案,页游平台网站,西安房价前言#xff1a; 最近在写需求的时候用到了DispatchGroup#xff0c;一直没有深入去学习#xff0c;既然遇到了那么就总结下吧。。。。 基本介绍#xff1a; 任务组#xff08;DispatchGroup#xff09;
DispatchGroup 可以将多个任务组合在一起并且监听它们的完成状态。…前言 最近在写需求的时候用到了DispatchGroup一直没有深入去学习既然遇到了那么就总结下吧。。。。 基本介绍 任务组DispatchGroup
DispatchGroup 可以将多个任务组合在一起并且监听它们的完成状态。当所有任务都完成时可以通过通知回调或等待的方式知道它们的执行结果。
let group DispatchGroup()
let queue DispatchQueue(label: .com1,attributes: .concurrent)queue.async(group: group) {print(任务1完成)
}queue.async(group: group) {print(任务2完成)
}// 当所有任务完成时通知
group.notify(queue: DispatchQueue.main) {print(所有任务完成)
}// 或者阻塞等待所有任务完成
group.wait()
print(所有任务完成等待方式)
输出 任务2完成 任务1完成 所有任务完成等待方式 所有任务完成 正文
Swift使用的GCD是桥接OC的源码。所以底层还是libdispatch。
可以去github上Apple官方仓库去下载GitHub - swiftlang/swift-corelibs-libdispatch: The libdispatch Project, (a.k.a. Grand Central Dispatch), for concurrency on multicore hardware 下载源码后可以在semaphore.c中找到DispatchGroup的实现。 create
先来看看dispatch_group_create的实现
dispatch_group_create(void)
{return _dispatch_group_create_with_count(0);
}
可以看到创建dispatch_group涉及到_dispatch_group_create_with_count(long count)
那我们看下_dispatch_group_create_with_count()的源码
DISPATCH_ALWAYS_INLINE
static inline dispatch_group_t
_dispatch_group_create_with_count(long count)
{//dispatch_group_t就是dispatchGroup//dispatch_group_t本质上就是dispatch_group_s 详见下方dispatch_group_t dg (dispatch_group_t)_dispatch_object_alloc(DISPATCH_VTABLE(group), sizeof(struct dispatch_group_s));//把count的值存进去结构体_dispatch_semaphore_class_init(count, dg);//如果有值 就执行os_atomic_store2oif (count) {os_atomic_store2o(dg, do_ref_cnt, 1, relaxed); // rdar://problem/22318411}return dg;
}
我们一个一个来分析
通过搜索发现dispatch_group_t本质上就是dispatch_group_s dispatch_group_s其实是一个结构体其代码如下
struct dispatch_group_s {DISPATCH_SEMAPHORE_HEADER(group, dg);//看名字知道和wait方法有关int volatile dg_waiters;//dispatch_continuation_s可以自行搜索 最后是个dispatch_object_s//这里可以理解为存储一个链表的 链表头和尾。看参数名知道和notify有关struct dispatch_continuation_s *volatile dg_notify_head;struct dispatch_continuation_s *volatile dg_notify_tail;
};
creat创建了一个dispatch_group_t也是dispatch_group_s出来默认传进来的count是0并且把count通过dispatch_semaphore_class_init(count, dg)存了起来。 我们再来看看dispatch_semaphore_class_init(count, dg)的代码
//_dispatch_semaphore_class_init(count, dg);
static void
_dispatch_semaphore_class_init(long value, dispatch_semaphore_class_t dsemau)
{ //dsemau就是dg 本质就是把传递进来的count存起来struct dispatch_semaphore_header_s *dsema dsemau._dsema_hdr;dsema-do_next DISPATCH_OBJECT_LISTLESS;dsema-do_targetq _dispatch_get_root_queue(DISPATCH_QOS_DEFAULT, false);//value就是传进来的countdsema-dsema_value value;_dispatch_sema4_init(dsema-dsema_sema, _DSEMA4_POLICY_FIFO);
}
通过creat方法我们知道我们创建了一个dispatch_group_s出来并且把0存了起来。知道dispatch_group_s中有一个类似链表的头和尾看参数名知道和notify有关。 enter
enter() 本质上调用dispatch_group_enter()
其代码如下
void
dispatch_group_enter(dispatch_group_t dg)
{//os_atomic_inc_orig2o是宏定义可以一直点进去看。本质上就是把dg的dg_value做1操作。long value os_atomic_inc_orig2o(dg, dg_value, acquire);if (slowpath((unsigned long)value (unsigned long)LONG_MAX)) {DISPATCH_CLIENT_CRASH(value,Too many nested calls to dispatch_group_enter());}if (value 0) {_dispatch_retain(dg); // rdar://problem/22318411}
}
其实dispatch_group_enter只是把dg的dg_value做一个1的操作。如果dg_value值过大就会crash。如果dg_value为0就会释放 leave()
void
dispatch_group_leave(dispatch_group_t dg)
{//dg_value -1long value os_atomic_dec2o(dg, dg_value, release);if (slowpath(value 0)) {//当value0 执行_dispatch_group_wakereturn (void)_dispatch_group_wake(dg, true);}//不成对出现 crashif (slowpath(value 0)) {DISPATCH_CLIENT_CRASH(value,Unbalanced call to dispatch_group_leave());}
}
与enter相反做减1操作。
从源码得知leave的核心逻辑是判断value0时候执行_dispatch_group_wake。同时当levae次数比enter多时候value0会crash
可以说DispatchGroup的核心逻辑就在_dispatch_group_wake方法中
_dispatch_group_wake
代码如下
DISPATCH_NOINLINE
static long
_dispatch_group_wake(dispatch_group_t dg, bool needs_release)
{dispatch_continuation_t next, head, tail NULL;long rval;// cannot use os_mpsc_capture_snapshot() because we can have concurrent// _dispatch_group_wake() calls//dispatch_group_s 中dg_notify_headhead os_atomic_xchg2o(dg, dg_notify_head, NULL, relaxed);if (head) {// snapshot before anything is notified/woken rdar://problem/8554546tail os_atomic_xchg2o(dg, dg_notify_tail, NULL, release);}rval (long)os_atomic_xchg2o(dg, dg_waiters, 0, relaxed);if (rval) {// wake group waiters_dispatch_sema4_create(dg-dg_sema, _DSEMA4_POLICY_FIFO);_dispatch_sema4_signal(dg-dg_sema, rval);}uint16_t refs needs_release ? 1 : 0; // rdar://problem/22318411if (head) {// async group notify blocksdo {next os_mpsc_pop_snapshot_head(head, tail, do_next);dispatch_queue_t dsn_queue (dispatch_queue_t)head-dc_data;//head就是notify的block 在目标队列dsn_queue上运行_dispatch_continuation_async(dsn_queue, head);_dispatch_release(dsn_queue);} while ((head next));refs;}if (refs) _dispatch_release_n(dg, refs);return 0;
}
是否还记得前面提到的dispatch_group_s中的链表头和尾 head os_atomic_xchg2o(dg, dg_notify_head, NULL, relaxed); _dispatch_group_wake的代码前半部分其实是这里取出dispatch_group_s中的链表头如果有链表头再取出链表尾。执行的真正逻辑在do_while中我们截出来研究
if (head) {// async group notify blocksdo {next os_mpsc_pop_snapshot_head(head, tail, do_next);dispatch_queue_t dsn_queue (dispatch_queue_t)head-dc_data;//head就是notify的block 在目标队列dsn_queue上运行_dispatch_continuation_async(dsn_queue, head);_dispatch_release(dsn_queue);} while ((head next));refs;}通过head-dc_data拿到目标队列然后通过_dispatch_continuation_async(dsn_queue, head)将head运行在目标队列上。
那么head其实就是任务队列这个队列中存储的是notify回调的block
这时候我们回头看dispatch_group_s的定义
struct dispatch_group_s {DISPATCH_SEMAPHORE_HEADER(group, dg);//看名字知道和wait方法有关int volatile dg_waiters;//这里就是把所有notify的回调block存进链表里然后拿到头结点和尾结点。struct dispatch_continuation_s *volatile dg_notify_head;struct dispatch_continuation_s *volatile dg_notify_tail;
};
总结
DispatchGroup 在创建时候会建立一个链表来存储notify的block回调。判断notify执行的依据就是dg_value是否为0当不调用enter和leave时候dg_value0notify的回调会立即执行并且有多个notify会按照顺序依次调用。当有enter时候dg_value1。leave时候-1。当最后一个leave执行后dg_value0。去循环链表执行notify的回调根据源码也得知enter和leave必须成对出现 当enter多的时候dg_value永远大于0notify不会被执行。 当leave多的时候dg_value小于0造成Crash 参考
从源码分析Swift多线程—DispatchGroup | licc
一文看懂iOS多线程并发(NSThread、GCD、NSOperationNSOperationQueue)_ios nsstread nsoperation gcd-CSDN博客
GitHub - swiftlang/swift-corelibs-libdispatch: The libdispatch Project, (a.k.a. Grand Central Dispatch), for concurrency on multicore hardware 文章转载自: http://www.morning.xdqrz.cn.gov.cn.xdqrz.cn http://www.morning.nfgbf.cn.gov.cn.nfgbf.cn http://www.morning.dnmwl.cn.gov.cn.dnmwl.cn http://www.morning.qrpdk.cn.gov.cn.qrpdk.cn http://www.morning.kntsd.cn.gov.cn.kntsd.cn http://www.morning.nkqxb.cn.gov.cn.nkqxb.cn http://www.morning.sqtsl.cn.gov.cn.sqtsl.cn http://www.morning.lbfgq.cn.gov.cn.lbfgq.cn http://www.morning.rzcfg.cn.gov.cn.rzcfg.cn http://www.morning.pkfpl.cn.gov.cn.pkfpl.cn http://www.morning.tgnr.cn.gov.cn.tgnr.cn http://www.morning.ylyzk.cn.gov.cn.ylyzk.cn http://www.morning.wqkfm.cn.gov.cn.wqkfm.cn http://www.morning.wzdjl.cn.gov.cn.wzdjl.cn http://www.morning.jqjnx.cn.gov.cn.jqjnx.cn http://www.morning.nlglm.cn.gov.cn.nlglm.cn http://www.morning.lsfbb.cn.gov.cn.lsfbb.cn http://www.morning.mnbgx.cn.gov.cn.mnbgx.cn http://www.morning.rcfwr.cn.gov.cn.rcfwr.cn http://www.morning.gwxwl.cn.gov.cn.gwxwl.cn http://www.morning.hhnhb.cn.gov.cn.hhnhb.cn http://www.morning.lqzhj.cn.gov.cn.lqzhj.cn http://www.morning.qmbpy.cn.gov.cn.qmbpy.cn http://www.morning.pcjw.cn.gov.cn.pcjw.cn http://www.morning.fqcdh.cn.gov.cn.fqcdh.cn http://www.morning.qichetc.com.gov.cn.qichetc.com http://www.morning.mkyxp.cn.gov.cn.mkyxp.cn http://www.morning.kxnjg.cn.gov.cn.kxnjg.cn http://www.morning.bygyd.cn.gov.cn.bygyd.cn http://www.morning.zlnkq.cn.gov.cn.zlnkq.cn http://www.morning.ynryz.cn.gov.cn.ynryz.cn http://www.morning.kqrql.cn.gov.cn.kqrql.cn http://www.morning.btwrj.cn.gov.cn.btwrj.cn http://www.morning.dygsz.cn.gov.cn.dygsz.cn http://www.morning.ypzsk.cn.gov.cn.ypzsk.cn http://www.morning.ppbqz.cn.gov.cn.ppbqz.cn http://www.morning.yfnhg.cn.gov.cn.yfnhg.cn http://www.morning.xbhpm.cn.gov.cn.xbhpm.cn http://www.morning.nylbb.cn.gov.cn.nylbb.cn http://www.morning.xmttd.cn.gov.cn.xmttd.cn http://www.morning.smygl.cn.gov.cn.smygl.cn http://www.morning.cttgj.cn.gov.cn.cttgj.cn http://www.morning.jqtb.cn.gov.cn.jqtb.cn http://www.morning.bpmz.cn.gov.cn.bpmz.cn http://www.morning.dtnzk.cn.gov.cn.dtnzk.cn http://www.morning.xcjbk.cn.gov.cn.xcjbk.cn http://www.morning.hsgxj.cn.gov.cn.hsgxj.cn http://www.morning.pzpj.cn.gov.cn.pzpj.cn http://www.morning.kklwz.cn.gov.cn.kklwz.cn http://www.morning.htqrh.cn.gov.cn.htqrh.cn http://www.morning.gktds.cn.gov.cn.gktds.cn http://www.morning.jqhrk.cn.gov.cn.jqhrk.cn http://www.morning.pqypt.cn.gov.cn.pqypt.cn http://www.morning.rxhn.cn.gov.cn.rxhn.cn http://www.morning.tdmr.cn.gov.cn.tdmr.cn http://www.morning.qfkxj.cn.gov.cn.qfkxj.cn http://www.morning.qlbmc.cn.gov.cn.qlbmc.cn http://www.morning.ngkgy.cn.gov.cn.ngkgy.cn http://www.morning.yxwnn.cn.gov.cn.yxwnn.cn http://www.morning.qqbw.cn.gov.cn.qqbw.cn http://www.morning.wqjpl.cn.gov.cn.wqjpl.cn http://www.morning.pltbd.cn.gov.cn.pltbd.cn http://www.morning.nynpf.cn.gov.cn.nynpf.cn http://www.morning.qmzhy.cn.gov.cn.qmzhy.cn http://www.morning.mpflb.cn.gov.cn.mpflb.cn http://www.morning.xdpjf.cn.gov.cn.xdpjf.cn http://www.morning.pqcsx.cn.gov.cn.pqcsx.cn http://www.morning.sjwzz.cn.gov.cn.sjwzz.cn http://www.morning.kggxj.cn.gov.cn.kggxj.cn http://www.morning.nslwj.cn.gov.cn.nslwj.cn http://www.morning.kclkb.cn.gov.cn.kclkb.cn http://www.morning.bpmdx.cn.gov.cn.bpmdx.cn http://www.morning.blqsr.cn.gov.cn.blqsr.cn http://www.morning.qllcp.cn.gov.cn.qllcp.cn http://www.morning.qkqpy.cn.gov.cn.qkqpy.cn http://www.morning.yrdn.cn.gov.cn.yrdn.cn http://www.morning.rysmn.cn.gov.cn.rysmn.cn http://www.morning.xlndf.cn.gov.cn.xlndf.cn http://www.morning.sfhjx.cn.gov.cn.sfhjx.cn http://www.morning.khxwp.cn.gov.cn.khxwp.cn