Как оптимизировать производительность слушателей изменения результатов в Realm (Swift) с глубокой иерархией? - PullRequest
0 голосов
/ 18 июня 2019

Мы используем Realm (Swift привязка в настоящее время в версии 3.12.0) с самых первых дней в нашем проекте. В некоторых ранних версиях до 1.0 Realm предусмотрены прослушиватели изменений для Results без предоставления наборов изменений.
Мы использовали это много, чтобы узнать, изменился ли конкретный список Results.

Позже ребята из Realm обменялись этим API с методами предоставления changeSet. Мы должны были переключиться и теперь плохо обращаемся с этим API только для того, чтобы узнать, изменилось ли что-либо в определенном списке (вставки, удаления, модификации).

Вместе с RxSwift мы написали собственную реализацию Results прослушивания изменений, которая выглядит следующим образом:

public var observable: Observable<Base> {
    return Observable.create { observer in
        let token = self.base.observe { changes in
            if case .update = changes {
                observer.onNext(self.base)
            }
        }

        observer.onNext(self.base)

        return Disposables.create(with: {
            observer.onCompleted()
            token.invalidate()
        })
    }
}

Когда мы теперь хотим получать последовательные обновления в списке, мы подписываемся так:

someRealm.objects(SomeObject.self).filter(<some filter>).rx.observable
    .subscribe(<subscription code that gets called on every update>)
    //dispose code missing

Мы написали расширение для RealmCollection, чтобы мы могли подписаться и на тип List.

Концепция равна подходу RxRealm.

Так что теперь в нашем приложении у нас есть много отфильтрованных списков / результатов, на которые мы подписываемся.

Когда данных становится все больше, мы замечаем значительные потери производительности, когда дело доходит до визуального изменения после записи чего-либо в БД.

Например: Допустим, у нас есть класс Car Realm Object с некоторыми свойствами и некоторыми отношениями 1-к-n и некоторыми 1-к-1. Одним из свойств является Bool, а именно isDriving. Теперь у нас есть много автомобилей, хранящихся в БД, и множество слушателей изменений с различными фильтрами, перечисляющими изменения коллекции автомобилей (наблюдатели коллекции слушают changeSets, чтобы узнать, был ли изменен список). Если я беру одну машину из какого-то списка и устанавливаю свойство isDriving с false на true (важно: мы делаем записи в фоновом режиме ), в идеале слушатель изменений запускается быстро, и у меня есть почти немедленный правильный ответ на мою запись в основном потоке .

Добавлено с правкой на 2019-06-19:


Давайте сделаем сценарий еще более реальным: Давайте изменим что-то по иерархии, скажем, название производителя шин. Скажем, Car имеет List<Tire>, Tire имеет Manufacturer и Manufacturer has a имя . Now we're still listing to Результаты collection changes with some more or less complex filters applied. Then we're changing the name of a Изготовитель`, который подключен к одной из шин, подключенных к одной из автомобили, которые находятся в этом фильтрованном списке.
Может ли это все еще быть быстро?


Очевидно, что когда длина результатов / списков, к которым прикреплены прослушиватели изменений, становится больше, внутреннему прослушивателю изменений 1062 * требуется больше времени для вычисления различий и запускается позже. Поэтому после записи мы видим изменения - в худшем случае - гораздо позже.

В нашем случае это неприемлемо. Итак, мы думаем о разных сценариях. Один из сценариев состоит в том, чтобы больше не использовать .observe в списках / результатах и ​​переключаться на Realm.observe, который срабатывает каждый раз, когда что-либо менялось в области, что не идеально, но это быстро, потому что процесс расчета изменений пропускается.

Мой вопрос: что я могу сделать, чтобы решить всю эту дилемму и снова сделать наше приложение быстрым?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...