Медленное удаление и сохранение во вложенном NSManagedObjectContext


В моем приложении у меня есть" мастер " NSPrivateQueueConcurrencyType контекст, который служит в качестве родителя для контекста NSMainQueueConcurrencyType, на который полагается контроллер вида и передает его. Я хотел сделать это, чтобы воспользоваться преимуществами асинхронного сохранения (это приложение использует iCloud с основными данными и сохраняет много работы по экспорту журналов вездесущности). Установка аналогична подходу Зарры, упомянутому в нижней части этой статьи

Сохранение в приложении обычно выглядит следующим образом:

[context save:nil];
[context.parentContext performBlock:^{
     [context.parentContext save:nil];
}];

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

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

На самом деле, я только что заметил, что салфетки для удаления удалений одного объекта несмотря на этот асинхронный шаблон сохранения, происходит заметная задержка, поэтому кажется, что все удаления в приложении происходят медленно.

Если, в качестве альтернативы, я выделяю новый контекст NSPrivateQueueConcurrencyType, устанавливаю его постоянный координатор хранилища в основной PSC в AppDelegate и выполняю удаление и сохранение, он по-прежнему выполняет много работы, но пользовательский интерфейс никогда не блокируется (но тогда мне приходится беспокоиться о координации контекстов, рефетчинге в основном контексте).

Есть идеи, что я мог сделать неправильно, или вы видели это поведение тоже?

1 5

1 ответ:

Удаление может занять длительное время. Они должны наладить все отношения. Есть несколько вещей, которые вы должны сделать, делая большие удаления.

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

Поток, выполняющий фактическую работу, управляется очередью FIFO, поэтому, если вы даете ему большую задача, которую нужно выполнить, она не сможет выполнять другие задачи, пока не завершится длительная.

Вероятно, вы используете FRC, и он пытается получать обновления, когда объекты и отношения меняются.

Если у вас есть большое удаление, вы можете изменить свою выборку, чтобы она только смотрела на текущий MOC для данных, пока происходит удаление. Когда удаление будет завершено, вы можете сказать запросу fetch, чтобы он вернулся к запросу до самого магазина сам.

Кроме того, при удалении большого количества материала лучше всего делать это небольшими кусками, внутри пула авторелиза, в отдельном потоке. Из этого фонового потока удаляйте небольшие фрагменты за один раз и делайте это с помощью performBlockAndWait. Таким образом, вы не загружаете очередь рабочего потока с запросами на удаление, и ваш поток пользовательского интерфейса может обрабатывать свои запросы. быстрее.

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