我阅读了文章:GCD global concurrent queue not always concurrent(iOS device)?,这是我想澄清的内容:
文档(https://developer.apple.com/documentation/dispatch/1431058-dispatch_block_cancel)表示无法取消开始执行的任务。
建议分配到全局并发队列中的任何块将自动开始执行,因此任何取消尝试都将实际上失败,这是否正确?
更具体地说-如果我排队1000个任务,而每个任务需要1000秒才能完成,这是否意味着在不到1000秒的时间内所有任务都将开始执行,而其中任何一个取消都会失败?
iOS和OSX的答案是否相同?
UPD:我想更清楚地说明这个问题。对于给定数量的任务,是否有可能大大超出设备的计算能力,是否有可能由于所有任务都在起始位置而无法取消在全局并发队列中排队的任务?
最佳答案
建议分配到全局并发队列中的任何块将自动开始执行,因此任何取消尝试都将实际上失败,这是否正确?
不完全的。首先,有点发麻:仅仅因为您已将某些内容分发到全局队列中并不能保证它已经开始。全局队列具有有限数量的工作线程,因此开始调度的任务的时间取决于资源的可用性。当然,如果队列空闲,那么它将通常很快启动,但是在竞争激烈的情况下,某些后者任务可能不会立即启动。
其次,该文档是正确的,如果您取消已经开始的任务,它将不会自动为您停止它。但是,如果我们(并且应该)编写定期检查dispatch_block_testcancel
(在Swift中为isCancelled
)的任务,并且如果终止,则可以实现此行为。例如:
- (void)testDispatchItem {
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
__block dispatch_block_t block = nil;
__weak typeof(self) weakSelf = self;
block = dispatch_block_create(0, ^{
for (long i = 0; i < 10000000; i++) {
if (dispatch_block_testcancel(block)) { break; }
NSLog(@"%ld", i);
[weakSelf heavyWork];
}
block = nil;
});
// start it
dispatch_async(queue, block);
// after five seconds, stop it if it hasn't already
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (block) { dispatch_block_cancel(block); }
});
}
...如果我入队1000个任务...
切勿将那么多任务分配到全局队列中,因为您将耗尽非常有限的(64个IIRC,尽管这可能会更改)工作线程。这可能导致各种问题,在某些情况下还可能导致死锁。请参阅WWDC 2015视频Building Responsive and Efficient Apps with GCD中的“引起死锁的线程爆炸”讨论。另请参阅WWDC 2016 Concurrent Programming With GCD in Swift 3。
对于给定数量的任务,是否有可能[显着]超过设备的计算能力,是否会出现这样一种情况,即我们无法取消在全局并发队列中排队的任务,因为它们都是[已启动]?
显然,尚未开始的任务将被取消。对于已经开始的那些任务,只要您正确测试取消状态,就没有问题了。