我有一个应用程序将长时间运行的进程(> 1分钟)放到NSOperationQueue(队列A)上。在队列A操作运行时,UI完全响应,完全如预期。把一个NSOperationQueue与NSOperation放在一个单独的NSOperationQueue上抢占NSOperation?
但是,我有一种不同的操作,用户可以在完全独立的NSOperationQueue(队列B)上执行这些操作。
当UI事件触发队列B上的操作的放置时,它必须等待直到队列A上的当前正在执行的操作完成后。这发生在iPod Touch(MC544LL)上。
我期望看到的是,任何放置到队列B上的操作都会或多或少地开始立即与队列A上的操作并行执行。这是我在模拟器上看到的行为。
我的问题是两个部分:
- 是我看到我的设备上的行为是基于现有文件预期?
- 使用NSOperation/NSOperationQueue,我如何通过在队列B上放置一个新的操作来预占队列A上的当前正在运行的操作?
注意:通过使用排队队列A/B的GCD队列,我可以得到完全的行为,所以我知道我的设备能够支持我想要做的事情。不过,我真的很想使用NSOperationQueue,因为这两个操作都需要被取消。
我有一个简单的测试应用程序:
的视图控制器是:
//
// ViewController.m
// QueueTest
//
#import "ViewController.h"
@interface ViewController()
@property (strong, nonatomic) NSOperationQueue *slowQueue;
@property (strong, nonatomic) NSOperationQueue *fastQueue;
@end
@implementation ViewController
-(id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
self.slowQueue = [[NSOperationQueue alloc] init];
self.fastQueue = [[NSOperationQueue alloc] init];
}
return self;
}
-(void)viewDidLoad
{
NSLog(@"View loaded on thread %@", [NSThread currentThread]);
}
// Responds to "Slow Op Start" button
- (IBAction)slowOpStartPressed:(id)sender {
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
[operation addExecutionBlock:^{
[self workHard:600];
}];
[self.slowQueue addOperation:operation];
}
// Responds to "Fast Op Start" button
- (IBAction)fastOpStart:(id)sender {
NSBlockOperation *operation = [[NSBlockOperation alloc] init];
[operation addExecutionBlock:^{
NSLog(@"Fast operation on thread %@", [NSThread currentThread]);
}];
[self.fastQueue addOperation:operation];
}
-(void)workHard:(NSUInteger)iterations
{
NSLog(@"SlowOperation start on thread %@", [NSThread currentThread]);
NSDecimalNumber *result = [[NSDecimalNumber alloc] initWithString:@"0"];
for (NSUInteger i = 0; i < iterations; i++) {
NSDecimalNumber *outer = [[NSDecimalNumber alloc] initWithUnsignedInteger:i];
for (NSUInteger j = 0; j < iterations; j++) {
NSDecimalNumber *inner = [[NSDecimalNumber alloc] initWithUnsignedInteger:j];
NSDecimalNumber *product = [outer decimalNumberByMultiplyingBy:inner];
result = [result decimalNumberByAdding:product];
}
result = [result decimalNumberByAdding:outer];
}
NSLog(@"SlowOperation end");
}
@end
予后第一次按下“慢运算开始”按钮看到的输出,接着约1秒后按“快速运算开始”按钮是:
2012-11-28 07:41:13.051 QueueTest[12558:907] View loaded on thread <NSThread: 0x1d51ec30>{name = (null), num = 1}
2012-11-28 07:41:14.745 QueueTest[12558:1703] SlowOperation start on thread <NSThread: 0x1d55e5f0>{name = (null), num = 3}
2012-11-28 07:41:25.127 QueueTest[12558:1703] SlowOperation end
2012-11-28 07:41:25.913 QueueTest[12558:3907] Fast operation on thread <NSThread: 0x1e36d4c0>{name = (null), num = 4}
正如你所看到的,第二个操作直到第一个操作完成后才开始执行,尽管事实上这是两个独立的(并且大概是独立的)NSOperationQueues。
我已阅读Apple Concurrency Guide,但没有发现任何描述这种情况的内容。我还阅读了两个关于相关主题的SO问题(link,link),但似乎都没有涉及到我看到的问题(抢先)。
其他的事情我已经试过:
- 设定每个的NSOperation
- 的queuePriority设置queuePriority每个的NSOperation同时将两种类型的操作在同一个队列
- 将两种操作到同一队列
此问题已经过多次编辑,可能会使某些评论/回答难以理解。
我看到你治好了症状,而我键入我的答案:-)我怀疑如果你需要NSOperationQueue的操作管理设施,并且不能使用GCD,让缓慢的操作队列序列将做你需要的。 –
@SimonLawrence,是的 - 我们的更新越过了路径:)。不幸的是,使用[slowQueue setMaxConcurrentOperationCount:1]创建队列串并没有帮助。有另一种方法吗? –
在你的问题的代码中,你将两个操作添加到同一个队列。错字或所有问题的原因? – jrturton