Является ли диспетчерская очередь GCD достаточной для ограничения контекста Core Data для одного потока

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

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

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

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

Ответы

Ответ 1

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


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

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

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

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

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

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

Ответ 2

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

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