ios NSOperation 和 NSOperationQueue 工作线程 vs 主线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19569244/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:33:27  来源:igfitidea点击:

NSOperation and NSOperationQueue working thread vs main thread

iosobjective-cmultithreadingnsoperationnsoperationqueue

提问by Zach

I have to carry out a series of download and database write operations in my app. I am using the NSOperationand NSOperationQueuefor the same.

我必须在我的应用程序中执行一系列下载和数据库写入操作。我正在使用NSOperationNSOperationQueue

This is application scenario:

这是应用场景:

  • Fetch all postcodes from a place.
  • For each postcode fetch all houses.
  • For each house fetch inhabitant details
  • 从一个地方获取所有邮政编码。
  • 对于每个邮政编码,获取所有房屋。
  • 获取每栋房屋的居民详细信息

As said, I have defined an NSOperationfor each task. In first case (Task1), I am sending a request to server to fetch all postcodes. The delegate within the NSOperationwill receive the data. This data is then written to database. The database operation is defined in a different class. From NSOperationclass I am making a call to the write function defined in database class.

如前所述,我NSOperation为每个任务定义了一个。在第一种情况(任务 1)中,我向服务器发送请求以获取所有邮政编码。中的委托NSOperation将接收数据。然后将此数据写入数据库。数据库操作在不同的类中定义。在NSOperation课堂上,我正在调用数据库类中定义的 write 函数。

My question is whether the database write operation occur in main thread or in a background thread? As I was calling it within a NSOperationI was expecting it to run in a different thread (Not MainThread) as the NSOperation. Can someone please explain this scenario while dealing with NSOperationand NSOperationQueue.

我的问题是数据库写操作是发生在主线程还是后台线程?当我在 a 中调用它时, NSOperation我希望它作为NSOperation. 有人可以在处理NSOperationand 时解释这种情况吗NSOperationQueue

回答by Rui Peres

My question is whether the database write operation occur in main thread or in a background thread?

我的问题是数据库写操作是发生在主线程还是后台线程?

If you create an NSOperationQueuefrom scratch as in:

如果您NSOperationQueue从头开始创建一个:

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];

It will be in a background thread:

它将在后台线程中:

Operation queues usually provide the threads used to run their operations. In OS X v10.6 and later, operation queues use the libdispatch library (also known as Grand Central Dispatch) to initiate the execution of their operations. As a result, operations are always executed on a separate thread, regardless of whether they are designated as concurrent or non-concurrent operations

操作队列通常提供用于运行其操作的线程。在 OS X v10.6 及更高版本中,操作队列使用 libdispatch 库(也称为 Grand Central Dispatch)来启动其操作的执行。因此,操作总是在单独的线程上执行,无论它们被指定为并发操作还是非并发操作

Unless you are using the mainQueue:

除非您使用的是mainQueue

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

You can also see code like this:

您还可以看到这样的代码:

NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];
[myQueue addOperationWithBlock:^{

   // Background work

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // Main thread work (UI usually)
    }];
}];

And the GCD version:

和 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)                          
              });
});

NSOperationQueuegives finer control with what you want to do. You can create dependencies between the two operations (download and save to database). To pass the data between one block and the other, you can assume for example, that a NSDatawill be coming from the server so:

NSOperationQueue可以更好地控制您想要做什么。您可以在两个操作(下载并保存到数据库)之间创建依赖关系。例如,要在一个块和另一个块之间传递数据,您可以假设 aNSData将来自服务器,因此:

__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];

Edit:Why I am using __weakreference for the Operations, can be found here. But in a nutshell is to avoid retain cycles.

编辑:为什么我使用__weak操作参考,可以在这里找到。但简而言之就是避免保留循环。

回答by serrrgi

If you want to perform the database writing operation in the background thread you need to create a NSManagedObjectContextfor that thread.

如果要在后台线程中执行数据库写入操作,则需要NSManagedObjectContext为该线程创建一个。

You can create the background NSManagedObjectContextin the start method of your relevant NSOperationsubclass.

您可以NSManagedObjectContext在相关NSOperation子类的 start 方法中创建背景。

Check the Apple docs for Concurrency with Core Data.

查看 Apple 文档中的Concurrency with Core Data。

You can also create an NSManagedObjectContextthat executes requests in its own background thread by creating it with NSPrivateQueueConcurrencyTypeand performing the requests inside its performBlock:method.

您还可以创建一个NSManagedObjectContext在其自己的后台线程中NSPrivateQueueConcurrencyType执行请求的performBlock:方法,方法是在其方法中创建并执行请求。

回答by ilya n.

From NSOperationQueue

NSOperationQueue

In iOS 4 and later, operation queues use Grand Central Dispatch to execute operations. Prior to iOS 4, they create separate threads for non-concurrent operations and launch concurrent operations from the current thread.

在 iOS 4 及更高版本中,操作队列使用 Grand Central Dispatch 来执行操作。在 iOS 4 之前,它们为非并发操作创建单独的线程并从当前线程启动并发操作。

So,

所以,

[NSOperationQueue mainQueue] // added operations execute on main thread
[NSOperationQueue new] // post-iOS4, guaranteed to be not the main thread

In your case, you might want to create your own "database thread" by subclassing NSThreadand send messages to it with performSelector:onThread:.

在您的情况下,您可能希望通过子类创建自己的“数据库线程”NSThread并使用performSelector:onThread:.

回答by Ashok

The execution thread of NSOperation depends on the NSOperationQueuewhere you added the operation. Look out this statement in your code -

NSOperation 的执行线程取决于NSOperationQueue您添加操作的位置。在您的代码中查看此语句-

[[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue class

All this assumes you have not done any further threading in mainmethod of NSOperationwhich is the actual monster where the work instructions you have (expected to be) written.

所有这些都假设您没有在main方法中进行任何进一步的线程处理,NSOperation而该方法是您(预期)编写的工作指令的实际怪物。

However, in case of concurrent operations, the scenario is different. The queue may spawn a thread for each concurrent operation. Although it's not guarrantteed and it depends on system resources vs operation resource demands at that pointin the system. You can control concurrency of operation queue by it's maxConcurrentOperationCountproperty.

但是,在并发操作的情况下,场景就不同了。队列可以为每个并发操作产生一个线程。虽然它没有保证,但它取决于系统资源与系统中那个点的操作资源需求。您可以通过它的maxConcurrentOperationCount属性来控制操作队列的并发性。

EDIT-

编辑-

I found your question interesting and did some analysis/logging myself. I have NSOperationQueue created on main thread like this -

我发现你的问题很有趣,并自己做了一些分析/记录。我在这样的主线程上创建了 NSOperationQueue -

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

And then, I went on to create an NSOperation and added it using addOperation. In the main method of this operation when i checked for current thread,

然后,我继续创建一个 NSOperation 并使用 addOperation 添加它。在此操作的主要方法中,当我检查当前线程时,

NSLog(@"Operation obj =  %@\n current thread = %@ \n main thread = %@", self, [NSThread currentThread], [NSThread mainThread]);

it was not as main thread. And, found that current thread object is not main thread object.

它不是主线程。并且,发现当前线程对象不是主线程对象。

So, custom creation of queue on main thread (with no concurrency among its operation) doesn't necessarily mean the operations will execute serially on main thread itself.

因此,在主线程上自定义创建队列(其操作之间没有并发)并不一定意味着操作将在主线程本身上串行执行。

回答by duncanwilcox

The summary from the docs is operations are always executed on a separate thread(post iOS 4 implies GCD underlying operation queues).

文档的摘要是operations are always executed on a separate thread(iOS 4 后暗示 GCD 底层操作队列)。

It's trivial to check that it is indeed running on a non-main thread:

检查它是否确实在非主线程上运行很简单:

NSLog(@"main thread? %@", [NSThread isMainThread] ? @"YES" : @"NO");

When running in a thread it's trivial to use GCD/libdispatch to run something on the main thread, whether core data, user interface or other code required to run on the main thread:

在线程中运行时,使用 GCD/libdispatch 在主线程上运行一些东西是微不足道的,无论是核心数据、用户界面还是在主线程上运行所需的其他代码:

dispatch_async(dispatch_get_main_queue(), ^{
    // this is now running on the main thread
});

回答by Holly

If you're doing any non-trivial threading, you should use FMDatabaseQueue.

如果您正在进行任何非平凡的线程处理,则应使用FMDatabaseQueue