Проблемы параллелизма с observable.observeOn () и общими ресурсами - PullRequest
2 голосов
/ 27 мая 2020

У меня есть наблюдаемое внутри функции. Функция выполняется в определенной очереди queueA, а наблюдаемый объект подписывается с помощью ObserverOn (schedulerB). В onNext я меняю переменную класса.

В другой функции я меняю ту же переменную класса из другой очереди.

Вот код, демонстрирующий мою ситуацию:

class SomeClass {

    var commonResource: [String: String] = [:]
    var queueA = DispatchQueue(label: "A")
    var queueB = DispatchQueue(label: "B")
    var schedulerB = ConcurrentDispatchQueueScheduler(queue: QueueB)       

    func writeToResourceInOnNext() {
        let obs: PublishSubject<String> = OtherClass.GetObservable()
        obs.observeOn(schedulerB)
           .subscribe(onNext: { [weak self] res in
            // this happens on queue B
            self.commonResource["key"] = res
        }
    }

    func writeToResource() {
        // this happens on queue A
        commonResource["key"] = "otherValue"
    }
}

Мой вопрос: могут ли возникнуть проблемы с параллелизмом, если commonResource изменяется в обоих местах одновременно?

Какова обычная практика для записи / чтения из класса / глобальные переменные внутри onNext в наблюдаемом с ObserverOn?

Всем спасибо!

1 Ответ

1 голос
/ 27 мая 2020

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

очевидным решением здесь является отправка в очередь B внутри writeToResource(), чтобы избежать состояния гонки.

Другой вариант - использовать NSLock (или NSRecursiveLock) и заблокировать его перед записью в ресурс и разблокировать его после.

Лучшая практика: когда у вас есть побочный эффект происходит внутри закрытия функции подписки (в данном случае запись в commonResource, что закрытие - это только место, где возникает побочный эффект. Это будет означать отказ от пассивной функции writeToResource() и вместо этого передать Observable, который был сгенерирован любым кодом, который в настоящее время вызывает функцию.

...