NSOperation и NSOperationQueue рабочий поток против основного потока
Я должен выполнить ряд операций загрузки и записи базы данных в моем приложении. Я использую NSOperation и NSOperationQueue то же самое. 
это сценарий применения:
- получить все почтовые индексы с места.
 - для каждого почтового индекса принести все дома.
 - для каждого дома принести жителя детали
 
как уже было сказано, я определил NSOperation для каждой задачи. В первом случае (Task1), я посылаю запрос сервер для получения всех почтовых индексов. Делегат внутри NSOperation получаете данные. Эти данные затем записываются в базу данных. Операция базы данных определяется в другом классе. От NSOperation класс я делаю вызов функции записи, определенные в классе базы данных.
мой вопрос заключается в том, происходит ли операция записи базы данных в основном потоке или в фоновом потоке? Как я называл его в пределах NSOperation Я ожидал, что он будет работать в другом потоке (не MainThread) в качестве NSOperation. Может кто-нибудь объяснить этот сценарий, имея дело с NSOperation и NSOperationQueue.
6 ответов:
мой вопрос заключается в том, происходит ли операция записи базы данных в main потоке или в фоновом потоке?
при создании
NSOperationQueueС нуля, как в:NSOperationQueue *myQueue = [[NSOperationQueue alloc] init];это будет в фоновом потоке:
очереди операций обычно предоставляют потоки, используемые для выполнения их оперативный. В OS X v10.6 и более поздних версиях очереди операций используют библиотека libdispatch (также известная как Grand Central Dispatch) для инициализации выполнение своих операций. в результате операции всегда выполняется в отдельном потоке, независимо от того, являются ли они назначается как параллельные или не параллельные операции
если вы используете
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дает более точный контроль, с тем, что вы хотите сделать. Вы можете создавать зависимости между двумя операциями (загрузка и сохранение в базу данных). Чтобы передать данные между одним блоком и другим, можно предположить, например, что 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: почему я использую
__weakссылка на операции, можно найти здесь. Но в двух словах, чтобы избежать удержания циклов.
если вы хотите выполнить операцию записи базы данных в фоновом потоке, вам нужно создать
NSManagedObjectContextна что-нить.вы можете создать фон
NSManagedObjectContextв методе запуска вашего соответствующегоNSOperationподкласс.проверьте документы Apple для параллелизм с основными данными.
вы также можете создать
NSManagedObjectContextкоторый выполняет запросы в своем собственном фоновом потоке, создавая его с помощьюNSPrivateQueueConcurrencyTypeи выполнение запросов внутри егоperformBlock:метод.
в iOS 4 и более поздних версиях операционные очереди используют Grand Central Dispatch для выполнения операций. До iOS 4 они создают отдельные потоки для неконкурентных операций и запускают параллельные операции из текущего потока.
и
[NSOperationQueue mainQueue] // added operations execute on main thread [NSOperationQueue new] // post-iOS4, guaranteed to be not the main threadв вашем случае вы можете создать свой собственный "поток базы данных" путем подкласса
NSThreadи отправлять сообщения на него сperformSelector:onThread:.
поток выполнения NSOperation зависит от
NSOperationQueueгде вы добавили операцию. Обратите внимание на это утверждение в вашем коде -[[NSOperationQueue mainQueue] addOperation:yourOperation]; // or any other similar add method of NSOperationQueue classвсе это предполагает, что вы не сделали никаких дальнейших потоков в
mainметодNSOperationкоторый является фактическим монстром, где рабочие инструкции, которые вы (как ожидается) написали.однако, в случае параллельных операций, сценарий отличается. Очередь может порождать поток для каждой параллельной операции. Хотя это не guarrantteed, и это зависит от системных ресурсов и требований к операционным ресурсам в этот момент в системе. Вы можете управлять параллелизмом очереди операций с помощью it's
maxConcurrentOperationCountсобственность.EDIT -
Я нашел ваш вопрос интересным и сделал некоторый анализ/протоколирование себя. У меня есть 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и затем, я пошел дальше, чтобы создать NSOperation и добавил его с помощью addOperation. В основном методе этой операции, когда я проверил для текущего потока,
NSLog(@"Operation obj = %@\n current thread = %@ \n main thread = %@", self, [NSThread currentThread], [NSThread mainThread]);это было не как основной поток. И обнаружил, что текущий объект потока не является основным объектом потока.
таким образом, пользовательское создание очереди в основном потоке (без параллелизма среди его операций) не обязательно означает, что операции будут выполняться последовательно в самом основном потоке.
резюме из документов
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.