Планировщики сетевых запросов в RxSwift - PullRequest
0 голосов
/ 22 октября 2018

Я изучаю Rxswift и применяю его в проекте с самого начала.Я хотел бы, чтобы ваша помощь стала более уверенной в отношении концепции.

Я понимаю, что изменения в пользовательском интерфейсе должны быть выполнены на Mainscheduler, и вы должны явно использовать .observeOn(MainSchedule…, если вы не используете Drivers.

Я сомневаюсь, что: обычно, следует ли мне явно переключаться на фоновый поток при выполнении сетевых запросов? .

Я не нашел много литературы, рассказывающей точноэто, но я прочитал код некоторых проектов, и большинство из них нет, но некоторые читают.Те, в конечном счете, используют Drivers или .observeOn(MainSchedule… для внесения изменений в пользовательский интерфейс.

В https://www.thedroidsonroids.com/blog/rxswift-examples-4-multithreading,, например, он говорит

So as you may guessed, in fact everything we did was done on a MainScheduler. Why? Because our chain starts from searchBar.rx_text and this one is guaranteed to be on MainScheduler. And because everything else is by default on current scheduler – well our UI thread may get overwhelmed. How to prevent that? Switch to the background thread before the request and before the mapping, so we will just update UI on the main thread

Итак, что он делает для решения проблемы, которую он упоминает, так это явно объявляет .observeOn(ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Background))

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

Это хорошая практика? Должен ли я в каждом запросе API явно переходить в фоновый режим, а затем возвращаться в основной режим только тогда, когда это необходимо?

Если это так, что будет лучшим способом? Комунаблюдать на заднем плане, а затем на главном?Или подписаться на фон и наблюдать за Main, как это сделано в этой сущности: https://gist.github.com/darrensapalo/711d33b3e7f59b712ea3b6d5406952a4?

Или, может быть, другим способом?

PS: извините за старый код, носреди ссылок, которые я нашел, они лучше соответствуют моему вопросу.

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

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

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

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

Мне также важно отметить, что вызов subscribeOn абсолютно бесполезен для любого сетевого уровня.Это только изменит поток, для которого запрос выполнен , не фоновый поток, ожидающий ответа, и поток, в котором ответ возвращается.Сетевой уровень решает, какой поток он использует для выталкивания данных, и subscribeOn не может его изменить.Лучшее, что вы можете сделать, это использовать observeOn для перенаправления потока данных в другой поток после ответа.Оператор subscribeOn предназначен для синхронных операций, а не сетевых запросов.

0 голосов
/ 22 октября 2018

Обычно, т. Е. Если вы не указываете какие-либо планировщики, Rx равно синхронный .

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

Фоновая работа, включая сетевые запросы, должна выполняться в фоновых планировщиках.Какие из них - зависит от приоритета и предпочтения одновременного / последовательного выполнения.

.subscribeOn() определяет, где выполняется работа, а .observeOn() определяет, где обрабатываются результаты.

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

Вы можете объявить планировщики так (просто пример):

static let main = MainScheduler.instance
static let concurrentMain = ConcurrentMainScheduler.instance

static let serialBackground = SerialDispatchQueueScheduler.init(qos: .background)
static let concurrentBackground = ConcurrentDispatchQueueScheduler.init(qos: .background)

static let serialUtility = SerialDispatchQueueScheduler.init(qos: .utility)
static let concurrentUtility = ConcurrentDispatchQueueScheduler.init(qos: .utility)

static let serialUser = SerialDispatchQueueScheduler.init(qos: .userInitiated)
static let concurrentUser = ConcurrentDispatchQueueScheduler.init(qos: .userInitiated)

static let serialInteractive = SerialDispatchQueueScheduler.init(qos: .userInteractive)
static let concurrentInteractive = ConcurrentDispatchQueueScheduler.init(qos: .userInteractive)

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

И резюме:

  • обычно, если я явно переключаюсь на фоновый поток при выполнениисетевые запросы?. - да, если библиотека не сделает это за вас

  • Должен ли я в каждом запросе API явно переходить в фоновый режим, а затем возвращаться обратно в Mainтолько когда это необходимо? - да

  • Если это так, что будет лучшим способом? [...] подписаться на фоне и наблюдать наОсновной

...