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
NSOperation and NSOperationQueue working thread vs main thread
提问by Zach
I have to carry out a series of download and database write operations in my app. I am using the NSOperation
and NSOperationQueue
for the same.
我必须在我的应用程序中执行一系列下载和数据库写入操作。我正在使用NSOperation
和NSOperationQueue
。
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 NSOperation
for each task. In first case (Task1), I am sending a request to server to fetch all postcodes. The delegate within the NSOperation
will receive the data. This data is then written to database. The database operation is defined in a different class. From NSOperation
class 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 NSOperation
I was expecting it to run in a different thread (Not MainThread) as the NSOperation
. Can someone please explain this scenario while dealing with NSOperation
and NSOperationQueue
.
我的问题是数据库写操作是发生在主线程还是后台线程?当我在 a 中调用它时, NSOperation
我希望它作为NSOperation
. 有人可以在处理NSOperation
and 时解释这种情况吗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 NSOperationQueue
from 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)
});
});
NSOperationQueue
gives 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 NSData
will 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 __weak
reference 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 NSManagedObjectContext
for that thread.
如果要在后台线程中执行数据库写入操作,则需要NSManagedObjectContext
为该线程创建一个。
You can create the background NSManagedObjectContext
in the start method of your relevant NSOperation
subclass.
您可以NSManagedObjectContext
在相关NSOperation
子类的 start 方法中创建背景。
Check the Apple docs for Concurrency with Core Data.
查看 Apple 文档中的Concurrency with Core Data。
You can also create an NSManagedObjectContext
that executes requests in its own background thread by creating it with NSPrivateQueueConcurrencyType
and performing the requests inside its performBlock:
method.
您还可以创建一个NSManagedObjectContext
在其自己的后台线程中NSPrivateQueueConcurrencyType
执行请求的performBlock:
方法,方法是在其方法中创建并执行请求。
回答by ilya n.
From 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 NSThread
and send messages to it with performSelector:onThread:
.
在您的情况下,您可能希望通过子类创建自己的“数据库线程”NSThread
并使用performSelector:onThread:
.
回答by Ashok
The execution thread of NSOperation depends on the NSOperationQueue
where 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 main
method of NSOperation
which 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 maxConcurrentOperationCount
property.
但是,在并发操作的情况下,场景就不同了。队列可以为每个并发操作产生一个线程。虽然它没有保证,但它取决于系统资源与系统中那个点的操作资源需求。您可以通过它的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。