NSOperation和NSOperationQueue工作线程vs主线程
我必须在我的应用程序中执行一系列下载和数据库写入操作。 我正在使用NSOperation
和NSOperationQueue
相同。
这是应用场景:
- 从一个地方获取所有邮编。
- 为每个邮政编码提取所有房屋。
- 为每个房子获取居民的细节
如上所述,我已经为每个任务定义了一个NSOperation
。 在第一种情况下(Task1),我发送一个请求到服务器来获取所有的邮编。 NSOperation
内的NSOperation
将收到数据。 这些数据被写入数据库。 数据库操作是在不同的类中定义的。 从NSOperation
类我正在调用数据库类中定义的写函数。
我的问题是数据库写操作是在主线程还是在后台线程中发生? 当我在一个NSOperation
调用它时,我期待它在NSOperation
中运行在不同的线程(Not MainThread)中。 有人可以在处理NSOperation
和NSOperationQueue
时解释这种情况。
我的问题是数据库写操作是在主线程还是在后台线程中发生?
如果你从头开始创build一个NSOperationQueue
,如下所示:
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
它将在后台线程中:
操作队列通常提供用于运行其操作的线程。 在OS X v10.6及更高版本中,操作队列使用libdispatch库(也称为Grand Central Dispatch)来启动其操作的执行。 因此,操作总是在单独的线程上执行 ,而不pipe它们是被指定为并发还是非并发操作
除非你使用mainQueue
:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
你也可以看到这样的代码:
NSOperationQueue *myQueue = [[NSOperationQueue alloc] init]; [myQueue addOperationWithBlock:^{ // Background work [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // Main thread work (UI usually) }]; }];
和GCD版本:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { // Background work dispatch_async(dispatch_get_main_queue(), ^(void) { // Main thread work (UI usually) }); });
NSOperationQueue
更好地控制你想要做什么。 您可以在两个操作之间创build依赖关系(下载并保存到数据库)。 要在一个块和另一个块之间传递数据,你可以假设一个NSData
将来自服务器,所以:
__block NSData *dataFromServer = nil; NSBlockOperation *downloadOperation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation *weakDownloadOperation = downloadOperation; [weakDownloadOperation addExecutionBlock:^{ // Download your stuff // Finally put it on the right place: dataFromServer = .... }]; NSBlockOperation *saveToDataBaseOperation = [[NSBlockOperation alloc] init]; __weak NSBlockOperation *weakSaveToDataBaseOperation = saveToDataBaseOperation; [weakSaveToDataBaseOperation addExecutionBlock:^{ // Work with your NSData instance // Save your stuff }]; [saveToDataBaseOperation addDependency:downloadOperation]; [myQueue addOperation:saveToDataBaseOperation]; [myQueue addOperation:downloadOperation];
编辑:为什么我使用__weak
参考的操作,可以在这里find。 但简而言之就是避免保留周期。
如果要在后台线程中执行数据库写入操作,则需要为该线程创build一个NSManagedObjectContext
。
你可以在相关NSOperation
子类的start方法中创build背景NSManagedObjectContext
。
核心数据检查苹果文档的并发性。
你也可以创build一个NSManagedObjectContext
,它通过在NSPrivateQueueConcurrencyType
创build它并在其performBlock:
方法内执行请求,在自己的后台线程中执行请求。
NSOperation的执行线程取决于添加操作的NSOperationQueue
。 看看你的代码中的这个声明 –
[[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue class
所有这一切都假定你没有对NSOperation
main
方法做进一步的线程化处理,这个方法就是你所写的工作指令的实际怪物。
但是,在并发操作的情况下,情况是不同的。 队列可能为每个并发操作产生一个线程。 虽然没有保证,但依赖于系统资源需求与系统当时的运营资源需求。 您可以通过它的maxConcurrentOperationCount
属性来控制操作队列的maxConcurrentOperationCount
性。
编辑 –
我发现你的问题很有趣,我自己做了一些分析/logging。 我有像这样在主线程上创buildNSOperationQueue –
self.queueSendMessageOperation = [[[NSOperationQueue alloc] init] autorelease]; NSLog(@"Operation queue creation. current thread = %@ \n main thread = %@", [NSThread currentThread], [NSThread mainThread]); self.queueSendMessageOperation.maxConcurrentOperationCount = 1; // restrict concurrency
然后,我继续创build一个NSOperation并使用addOperation添加它。 在这个操作的主要方法,当我检查当前线程,
NSLog(@"Operation obj = %@\n current thread = %@ \n main thread = %@", self, [NSThread currentThread], [NSThread mainThread]);
这不是主线。 而且,发现当前线程对象不是主线程对象。
所以,在主线程上自定义创build队列(在其操作中没有并发)并不一定意味着操作将在主线程本身上串行执行。
从NSOperationQueue
在iOS 4及更高版本中,操作队列使用Grand Central Dispatch来执行操作。 在iOS 4之前,他们为非并发操作创build单独的线程,并从当前线程启动并发操作。
所以,
[NSOperationQueue mainQueue] // added operations execute on main thread [NSOperationQueue new] // post-iOS4, guaranteed to be not the main thread
在你的情况下,你可能想创build自己的“数据库线程”通过NSThread
并发送消息给它与performSelector:onThread:
文档中的总结是operations are always executed on a separate thread
(iOS 4后隐含GCD基础操作队列)。
检查它确实在非主线程上运行是微不足道的:
NSLog(@"main thread? %@", [NSThread isMainThread] ? @"YES" : @"NO");
在线程中运行时,使用GCD / libdispatch在主线程上运行某些内容(无论核心数据,用户界面还是在主线程上运行所需的其他代码)是微不足道的:
dispatch_async(dispatch_get_main_queue(), ^{ // this is now running on the main thread });
如果你正在做任何不平凡的线程,你应该使用FMDatabaseQueue 。