我有一個應用程序將長時間運行的進程(> 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