我正在尝试验证dispatch_barrier_async
的功能,并使用“兴趣点”来检查发生了什么。
代码如下:
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (int index = 0; index < 3; ++index) {
kdebug_signpost_start(0, 0, 0, 0, 0);
dispatch_sync(_syncQueue, ^{
NSLog(@"sync@@@@@@ >>>> %d ",index);
sleep(1);
NSLog(@"sync@@@@@@ <<<< %d ",index);
});
kdebug_signpost_end(0, 0, 0, 0, 0);
}
for (int index = 3; index < 6; ++index) {
kdebug_signpost_start(1, 0, 0, 0, 1);
dispatch_barrier_async(_syncQueue, ^{
NSLog(@"sync===== >>>> %d ",index);
sleep(1);
NSLog(@"sync===== <<<< %d ",index);
});
kdebug_signpost_end(1, 0, 0, 0, 1);
}
for (int index = 6; index < 9; ++index) {
kdebug_signpost_start(2, 0, 0, 0, 2);
dispatch_sync(_syncQueue, ^{
NSLog(@"sync***** >>>> %d ",index);
sleep(1);
NSLog(@"sync***** <<<< %d ",index);
});
kdebug_signpost_end(2, 0, 0, 0, 2);
}
我希望
dispatch_barrier_async
调度的所有任务(第二个循环)应该在执行完成的任务完成后工作;以及
一旦dispatch_barrier_async
调度的任务开始工作,就无法运行同一队列中的其他任务。
但结果如下:
sync@@@@@@ >>>> 0
sync@@@@@@ <<<< 0
sync@@@@@@ >>>> 1
sync@@@@@@ <<<< 1
sync@@@@@@ >>>> 2
sync@@@@@@ <<<< 2
sync***** >>>> 6
sync===== >>>> 3
sync===== >>>> 4
sync===== >>>> 5
sync***** <<<< 6
sync***** >>>> 7
sync===== <<<< 3
sync===== <<<< 4
sync===== <<<< 5
sync***** <<<< 7
sync***** >>>> 8
我的困惑如下:
由于任务6已经在任务3之前启动,而任务3是dispatch_barrier_async
调度任务,为什么taks 3不等待任务6完成然后启动?这违反了我的期望a);
在dispatch_barrier_async调度任务5开始工作后,在任务5完成之前启动另一个任务7,这违反了我的期望b)
醇>我使用“兴趣点”工具来调试它,但似乎第二个循环没有显示在由仪器生成的图形上。这是我第一次使用这个工具,有人可以帮助指出这里的问题是什么吗?
[04/02] 谢谢Rob。按照你的建议后,这里有一些更新。
UPDATE1: 将第二个循环的队列创建方法更改为dispatch_queue_create后,效果很好。 dispatch_barrier_async调度的任务将等待它们完成之前的任务。并且他们之后的任务将启动它们(由dispatch_barrier_async调度的任务)完成。
UPDATE2: 然后我使用了你提供的代码,并将第二个循环的队列创建更改回dispatch_async,它们也可以作为期望。 但是,“兴趣点”图形存在一些问题。第二个循环中的某些任务无法正确显示。
Xcode指示(0x4 0x0 0x0 0x1)和(0x5 0x0 0x0 0x1)的某些错误,因为“无法将间隔记录为间隔,因为无法确定启动。”
< / LI>未列出(0x3 0x0 0x0 0x1),但(0x5 0x0 0x0 0x1)列出两次。并且图形上只显示一个(0x5 0x0 0x0 0x1)
我从未在“兴趣点”工具中看到指标。。
这会产生以下信息:
00:00.000.000 2ndLoop(KDebug Interval Signpost)以test.app(pid:64903,tid:0x1619027)结束,带参数:(0x4 0x0 0x0 0x1)。间隔不能记录为间隔,因为无法确定启动。 __kdebug_trace64←(8其他帧)
00:00.000.000 2ndLoop(KDebug Interval Signpost)以test.app(pid:64903,tid:0x1619028)结束,带参数:(0x5 0x0 0x0 0x1)。间隔不能记录为间隔,因为无法确定启动。 __kdebug_trace64←(8其他帧)
00:04.134.364 2ndLoop(KDebug Interval Signpost),由test.app(pid:64903,tid:0x1619028)启动,带参数:(0x5 0x0 0x0 0x1),1.00 s后由test.app结束(pid :64903,tid:0x1619026),带参数:(0x3 0x0 0x0 0x1)__ kdebug_trace64←(9其他帧)
答案 0 :(得分:2)
有两个不同的问题:
您不能对全局队列使用障碍。屏障说“当这个调度的任务正在运行时,不要在这个队列上运行任何东西”,所以当你尝试在全局队列上执行操作时,操作系统显然不喜欢它。正如the documentation所说,它只会对自定义并发队列而不是全局队列构成障碍:
您指定的队列应该是您使用
dispatch_queue_create
函数自己创建的并发队列。如果传递给此函数的队列是串行队列或全局并发队列之一,则此函数的行为类似于dispatch_async
函数
创建自己的并发队列,它应该按预期工作。
dispatch_queue_t queue = dispatch_queue_create("com.domain.app.test", DISPATCH_QUEUE_CONCURRENT);
产量:
您的“兴趣点”图表显示了调度过程(即主线程正在占用多少时间),而不是任务的运行本身。所以在你的第二次循环迭代中,它们的异步调度每次只需要25.54,5.17和4.72μs(微秒)。这就是为什么你没有在“兴趣点”工具中以图形方式看到你的第二次迭代。它们发生得太快而无法用图形表示。 (顺便说一句,这是一件非常好的事情,也就是我们从不同步调度慢任务的原因;我们绝不想阻止主线程。)
通常,在诊断GCD行为时,我发现“兴趣点”区域对于表示任务的运行更有用,而不是任务的调度。
要实现这一点,将kdebug
语句放在块中可能更有用,从而产生上图。因此:
dispatch_queue_t queue = dispatch_queue_create("com.domain.app.test", DISPATCH_QUEUE_CONCURRENT);
for (int index = 0; index < 3; ++index) {
dispatch_sync(queue, ^{
kdebug_signpost_start(0, index, 0, 0, 0);
sleep(1);
kdebug_signpost_end(0, index, 0, 0, 0);
});
}
for (int index = 3; index < 6; ++index) {
dispatch_barrier_async(queue, ^{
kdebug_signpost_start(1, index, 0, 0, 1);
sleep(1);
kdebug_signpost_end(1, index, 0, 0, 1);
});
}
for (int index = 6; index < 9; ++index) {
dispatch_sync(queue, ^{
kdebug_signpost_start(2, index, 0, 0, 2);
sleep(1);
kdebug_signpost_end(2, index, 0, 0, 2);
});
}
在修改后的问题中,您要问:
然后我使用了您提供的代码,并将第二个循环的队列创建更改回dispatch_async,它们也可以作为期望。但是,“兴趣点”图形存在一些问题。第二个循环中的某些任务无法正确显示。
Xcode指示(0x4 0x0 0x0 0x1)和(0x5 0x0 0x0 0x1)的某些错误,因为“无法将间隔记录为间隔,因为无法确定启动。”
< / LI>- 醇>
未列出(0x3 0x0 0x0 0x1),但(0x5 0x0 0x0 0x1)列出两次。并且图形上只显示一个(0x5 0x0 0x0 0x1)
“兴趣点”的诀窍在于,在执行GCD时,它会重用工作线程,因此如何匹配开始和结束kdebug
调用会产生混淆。如果您注意到,在我的示例中,我将循环编号作为“code”参数传递给kdebug
调用,迭代编号作为之后的第一个参数。然后我转到乐器中的“录音选项”并通过(a)代码告诉它匹配开始/结束调用; (b)代码后面的第一个参数:
你继续问:
- 我从未在“兴趣点”工具中看到指标。。
醇>
好吧,如果你想看到这些内容,你必须发帖,请看下面的kdebug_signpost
来电(而不是之前显示的kdebug_signpost_start
和kdebug_signpost_end
来电),例如:
dispatch_queue_t queue = dispatch_queue_create("com.domain.app.test", DISPATCH_QUEUE_CONCURRENT);
for (int index = 0; index < 3; ++index) {
kdebug_signpost(0, index, 0, 0, 0);
dispatch_sync(queue, ^{
kdebug_signpost_start(0, index, 0, 0, 0);
sleep(1);
kdebug_signpost_end(0, index, 0, 0, 0);
});
}
for (int index = 3; index < 6; ++index) {
kdebug_signpost(1, index, 0, 0, 0);
dispatch_barrier_async(queue, ^{
kdebug_signpost_start(1, index, 0, 0, 1);
sleep(1);
kdebug_signpost_end(1, index, 0, 0, 1);
});
}
for (int index = 6; index < 9; ++index) {
kdebug_signpost(2, index, 0, 0, 0);
dispatch_sync(queue, ^{
kdebug_signpost_start(2, index, 0, 0, 2);
sleep(1);
kdebug_signpost_end(2, index, 0, 0, 2);
});
}
产量:
再次注意,红色Ⓢ标志表示我从主线程发出调度电话时,彩色区域表示任务的时间安排。
我建议你观看WWDC 2016视频System Trace in Depth,了解有关如何使用“兴趣点”工具的详细信息。