调度队列:如何判断它们是否正在运行以及如何停止它们
我只是在玩 GCD,并且编写了一个 CoinFlipper 玩具应用程序。
下面是抛硬币的方法:
- (void)flipCoins:(NSUInteger)nFlips{
// Create the queues for work
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
// Split the number of flips into whole chunks of kChunkSize and the remainder.
NSUInteger numberOfWholeChunks = nFlips / kChunkSize;
NSUInteger numberOfRemainingFlips = nFlips - numberOfWholeChunks * kChunkSize;
if (numberOfWholeChunks > 0) {
for (NSUInteger index = 0; index < numberOfWholeChunks; index++) {
dispatch_async(queue, ^{
NSUInteger h = 0;
NSUInteger t = 0;
flipTheCoins(kChunkSize, &h, &t);
dispatch_async(mainQueue, ^{
self.nHeads += h;
self.nTails += t;
});
});
}
}
if (numberOfRemainingFlips > 0) {
dispatch_async(queue, ^{
NSUInteger h = 0;
NSUInteger t = 0;
flipTheCoins(numberOfRemainingFlips, &h, &t);
dispatch_async(mainQueue, ^{
self.nHeads += h;
self.nTails += t;
});
});
}
}
如你所见;我将翻转次数分成大块,在后台翻转它们并更新主队列中的属性。窗口控制器正在观察这些属性,并且 UI 会根据运行结果进行更新。
我浏览了并发编程指南和 GCD 文档,虽然有一种方法可以挂起队列,但没有办法阻止它们,并删除所有排队且未运行的对象。
我希望能够连接一个“停止”按钮来取消翻转开始后的操作。通过 NSOperationQueue,我可以观察 operationCount 属性来了解它是否正在运行,并使用 cancelAllOperations 来删除排队的块。
我浏览了并发编程指南和 GCD 文档,虽然有一种方法可以挂起队列,但没有办法阻止它们,并删除所有排队且未运行的对象。
那么:-
- 如何判断我添加到队列中的块是否仍在等待?
- 如何取消尚未运行的块?
- 我是 GCD 的新手,所以我这样做对吗?
I'm just playing around with GCD and I've written a toy CoinFlipper app.
Here's the method that flips the coins:
- (void)flipCoins:(NSUInteger)nFlips{
// Create the queues for work
dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
// Split the number of flips into whole chunks of kChunkSize and the remainder.
NSUInteger numberOfWholeChunks = nFlips / kChunkSize;
NSUInteger numberOfRemainingFlips = nFlips - numberOfWholeChunks * kChunkSize;
if (numberOfWholeChunks > 0) {
for (NSUInteger index = 0; index < numberOfWholeChunks; index++) {
dispatch_async(queue, ^{
NSUInteger h = 0;
NSUInteger t = 0;
flipTheCoins(kChunkSize, &h, &t);
dispatch_async(mainQueue, ^{
self.nHeads += h;
self.nTails += t;
});
});
}
}
if (numberOfRemainingFlips > 0) {
dispatch_async(queue, ^{
NSUInteger h = 0;
NSUInteger t = 0;
flipTheCoins(numberOfRemainingFlips, &h, &t);
dispatch_async(mainQueue, ^{
self.nHeads += h;
self.nTails += t;
});
});
}
}
As you can see; I'm breaking the number of flips into large chunks flipping them in the background and updating properties in the main queue. The properties are being observed by the window controller and an UI is updated with the running results.
I've looked through the Concurrency Programming Guide and the GCD docs, and although there is a way to suspend a queue, there isn't a way to stop them, and remove all queued and not running objects.
I'd like to be able to hook up a 'stop' button to cancel flipping once it's started. With NSOperationQueue
I can observe the operationCount
property to know if it's running, and cancelAllOperations
to remove queued blocks.
I've looked through the Concurrency Programming Guide and the GCD docs, and although there is a way to suspend a queue, there isn't a way to stop them, and remove all queued and not running objects.
So :-
- How do I tell if blocks I've added to a queue are still waiting?
- How do I cancel blocks that haven't run yet?
- I'm new to the GCD stuff, so am I doing it right?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是使用 GCD 编程时一个半常见的问题。
简而言之,GCD 没有用于队列的取消 API。基本原理:
考虑到所有这些情况,编写如下代码会更加高效和强大:
哦,要知道队列是否已完成运行所有排队的块,您的代码可以简单地使用同步执行一个空块 API:
正如评论中提到的,了解工作何时完成的更好方法是使用调度组。将所有块分派到该组,然后您可以向该组添加完成处理程序。一旦工作完成,完成块就会运行。
一旦所有块完成,该组将为空并触发通知块。从那里,您可以更新 UI 等。
祝您好运,玩得开心!
This is a semi-common question when programming with GCD.
The short answer is that GCD does not have a cancelation API for queues. The rationale:
Given all of these cases, it is far more efficient and powerful to write code like this:
Oh, and to know if a queue has finished running all of the enqueued blocks, your code can simply execute an empty block with the synchronous API:
As mentioned in the comments, a better way of knowing when your work is done is to use dispatch groups. Dispatch all your blocks to the group and then you can add a completion handler to the group. Once the work is complete, the completion block will run.
Once all of your blocks have completed, the group will be empty and trigger the notification block. From there, you can update UI, etc.
Good luck and have fun!
如何判断是否正在运行
在应用程序中进行测试
结果
可以将变量
maxWaitTime
的默认值调整为想要的结果。How to tell if is running
To test in app
Result
The default value for the variable
maxWaitTime
can be tweaked to wanted result.如果您有一个串行调度队列或并发调度队列,这里的代码可以做同样的事情。
If you have a serial dispatch queue OR a concurrent dispatch queue, here is a code that can do the same thing.