Достаточно ли очереди отправки GCD, чтобы ограничить контекст Core Data одним потоком? - PullRequest
15 голосов
/ 11 октября 2011

Я начинаю думать, что ответ на мой вопрос «Нет», но я все еще смущен и не уверен в этом. Поэтому, пожалуйста, подтвердите. Я уже осознал необходимость быть осторожным при использовании Core Data с несколькими потоками. NSManagedObjectContext объекты не должны пересекать границы потока. Будучи новичком и с потоками, и с Core Data, я с радостью обнаружил, что GCD должен облегчить это.

Возможно, наивно, тогда я подумал, что просто создам выделенную очередь отправки GCD для работы с базовыми данными (или даже, если необходимо, создаю несколько очередей отправки, каждая со своим собственным контекстом данных ядра). Это было бы просто.

Но теперь я понимаю, что одно большое преимущество очередей диспетчеризации GCD состоит в том, что он управляет несколькими потоками и использует их по мере необходимости. Поэтому, если я правильно понимаю, задачи, которые я передаю в одну и ту же очередь отправки, могут в конечном итоге выполняться в разных потоках, потенциально передавая контекст основных данных из одного потока в другой и приводя к ошибкам. Это верно?

Я прочитал много связанных вопросов и ответов, например, Основные данные и потоки / Grand Central Dispatch , но я несколько запутался. Принятый ответ на этот вопрос с использованием очередей GCD гарантирует, что в каждом потоке создается новый контекст, но не указывает на необходимость сделать это. Другой ответ гласит: «Вы можете выполнить всю работу с CoreData в очереди с именем com.yourcompany.appname.dataaccess», что подразумевает, что, пока работа с основными данными ограничена одной очередью отправки GCD, все в порядке. Может быть, это не так.

Ответы [ 2 ]

20 голосов
/ 11 октября 2011

Обновление: Как отмечает @adib в комментарии, подход к сериализованному доступу к контексту управляемого объекта изменился в iOS 9 и MacOS X 10.11. NSConfinementConcurrencyType, стратегия ограничения потока, теперь устарела в пользу NSPrivateQueueConcurrencyType и NSMainQueueConcurrencyType. Другими словами, прекратите использовать потоки для одновременного доступа к объектам Core Data и вместо этого начните использовать GCD. Вы должны использовать либо основную очередь отправки, либо ту, что связана с MOC, в зависимости от того, как вы настраиваете MOC, а не очередь вашего собственного создания. Это легко сделать, используя методы NSManagedObject -performBlock: или -performBlockAndWait:.


Краткий ответ: Использование очереди последовательной отправки может обеспечить сериализованный доступ к контексту управляемого объекта, и это приемлемый способ реализации стратегии «ограничения потока», даже если GCD может фактически использовать несколько потоков.

Более длинный ответ:

Принятый ответ на этот вопрос с использованием очередей GCD обеспечивает что новый контекст создается в каждом потоке, но не указывает на необходимость сделать это.

Важно помнить, что вы должны избегать изменения контекста управляемого объекта из двух разных потоков одновременно . Это может привести контекст в противоречивое состояние, и ничего хорошего из этого не выйдет. Таким образом, вид очереди отправки, которую вы используете, важен: параллельная очередь отправки позволяет одновременно выполнять несколько задач, и если они обе используют один и тот же контекст, у вас будут проблемы. Если вы используете очередь последовательной отправки, с другой стороны, две или более задач могут выполняться в разных потоках, но задачи будут выполняться по порядку, и одновременно будет выполняться только одна задача. Это очень похоже на выполнение всех задач в одном потоке, по крайней мере, в том, что касается поддержания согласованности контекста.

См. этот вопрос и ответ для более подробного объяснения.

Вот как Core Data всегда работали. Раздел Параллельность с базовыми данными в Руководстве по программированию базовых данных дает советы о том, как действовать, если вы решили использовать один контекст в нескольких потоках. В основном речь идет о необходимости быть очень осторожным, чтобы блокировать контекст каждый раз, когда вы получаете к нему доступ. Однако смысл всей этой блокировки заключается в том, чтобы два или более потока не пытались использовать контекст одновременно. Использование сериализованной очереди отправки позволяет достичь той же цели: поскольку одновременно выполняется только одна задача в очереди, нет никаких шансов, что две или более задач будут пытаться использовать контекст одновременно.

0 голосов
/ 27 января 2012

AFAIK ты прав;GCD не дает гарантий относительно потока, в котором выполняется очередь.Блоки и вызовы функций, отправленные в очередь, будут выполняться по одному, но если Core Data что-то делает с текущим потоком, например, устанавливает источник цикла выполнения или наблюдателя, то, вероятно, все будет работать не так, как задумано.

Однако в Mac OS X 10.7 NSManagedObjectContext можно настроить для запуска в основном потоке, в отдельном потоке или в частной очереди.

...