NSNotificationCenter против делегирования - что быстрее?
Я много читал о плюсах и минусах каждого, и я знаю, что делегаты обычно для одного слушателя, а уведомления - для многих. Вопрос о производительности.
Я читал это: NSNotificationCenter против делегирования (используя протоколы)?
Я посылаю звуковые сигналы от микрофона, в другой класс путем уведомления. я знаю, что здесь я должен использовать делегата, но мой вопрос: будут ли делегаты быстрее? потому что я вижу, что у меня проблема с частотой кадров (уменьшена), и я хотел бы знать, может ли причиной быть использование уведомления вместо делегата, или нет отношения?
Ответы
Ответ 1
Делегаты приходят с меньшими накладными расходами и поэтому будут выполняться намного быстрее.
Однако, в общем, вы должны смотреть на темы производительности только там, где они, вероятно, будут проблемой вообще. Для однократных задач, таких как отправка уведомления и вызов делегата, это никогда не должно быть проблемой. Но когда вы планируете выполнять их в цикле с переменной (в зависимости от данных) количеством интрасаций или для нескольких объектов данных, где вы извлекли или получили данные, не можете предсказать, сколько из них будет - это ситуации, когда Я бы рассмотрел оптимизацию производительности.
Ответ 2
Для тех, кто заинтересован в производительности, я быстро провел простой тест с использованием API-интерфейса XCTest measureBlock
. Короткий ответ заключается в том, что при вызове в цикле разница будет существенной.
Вот код, используемый для тестирования:
public protocol MyTestClassDelegate: class {
func myTestDelegateCallback()
}
public let TestClassValueChangedNotification = "TestClassNotification"
public class MyViewModel {
public weak var delegate: MyTestClassDelegate?
public init() { }
public func doNotification() {
NSNotificationCenter.defaultCenter().postNotificationName(TestClassValueChangedNotification, object: nil)
}
public func doDelegation(value: Int) {
delegate?.myTestClassDelegateCallback()
}
}
И тестовые случаи:
func testPerformanceNotifiction() {
measureBlock { () -> Void in
let testClass = MyTestClass()
for i in 0...100000 {
testClass.doNotification(i)
}
}
}
func testPerformanceDelegation() {
measureBlock { () -> Void in
let testClass = MyTestClass()
testClass.delegate = self
for i in 0...100000 {
testClass.doDelegation(i)
}
}
}
Результаты:
- Делегация: - - - - - - - 0.957 секунд
- Центр уведомлений: - 3.882 секунд
A Crappy Alternative я Пробовал
Другие соображения состоят в том, что производительность NSNotificationCenter, очевидно, может варьироваться в зависимости от количества слушателей для данного события и производительности кода, выполняемого этими слушателями. Также стоит отметить, что NSNotificationCenter синхронно вызывает слушателей уведомлений и в том же потоке, на который был вызван postNotification
, который может быть получен при первом приближении к NSNotificationCenter.
Если вы находите себя в сценарии (как и я), где вам нужно общение от одного до большого и высокая производительность, вы можете просто реализовать массив делегатов. Но вам не нужно беспокоиться, потому что выполнение этого на самом деле является худшим вариантом.
public func doMultipleDelegatation() {
for i in 0..<delegates.count {
delegates[i].myTestDelegateCallback()
})
}
func testPerformanceMultipleDelegation() {
measureBlock { () -> Void in
let testClass = MyTestClass()
testClass.delegates = [self]
for i in 0...100000 {
testClass.doMultipleDelegation(i)
}
}
}
Конечные результаты:
- Делегация: - - - - - - - 0.957 секунд
- Центр уведомлений: - 3.882 секунд
- Несколько делеций: - 6.488 секунд
Ответ 3
Делегаты работают быстрее.
Проблема с частотой кадров во время записи не связана с делегатами или уведомлениями. Это потому, что вы выполняете все свои задачи в основном потоке, который также отображает пользовательский интерфейс.
Ответ 4
Я знаю, что здесь я должен использовать делегата, НО мой вопрос: делает делегаты будут быстрее?
Это легко: попробуйте поделиться результатами!
Делегат, когда соотношение 1:1, точка-точка может быть быстрее, чем 1: m, публикует и подписывается в любой системе.
Быстрее ответить трудно, потому что это зависит от среды.
Когда не много слушателей, и издателю не нужно много искать для слушателей, тогда должна быть аналогичная производительность, но когда миллион подписчиков и их нужно искать, тогда может быть задержкой, снижением частоты кадров.
Ответ 5
Вызов делегата - это всего лишь вызов метода, но когда используются уведомления, необходимо сделать еще несколько вещей за кулисами для доставки вашего уведомления. Учитывая это - делегат идет немного быстрее.
Обработка звука в реальном времени - сложная задача, и я склонен думать, что вызов делегата или отправка уведомления приносят гораздо меньше затрат, чем ваш код обработки аудио.
UPDATE
Учитывая проблемы с производительностью, вы всегда должны выполнять измерения при различных подходах.
Ответ 6
Делегат будет быстрее уведомления, но не обязательно, что вам нужно. Для аудио вы, вероятно, должны сначала измерить. Если вам нужно что-то выполнить быстрее, прежде чем обновлять пользовательский интерфейс, вам следует взглянуть на перемещение некоторой задачи обработки в другой поток через диспетчер GCD или NSOperation.
Ответ 7
NotificationCenter достаточно быстр.
Во-первых, я протестировал синхронный случай публикации и получения уведомления в основном потоке, сравнив его с вызовом метода self:
Method call: .036 ms
Notification: .13 ms
Каждое число является наихудшим случаем среди 100 вызовов.
Поскольку уведомление в этом худшем случае составляет примерно одну десятую миллисекунды медленнее, это, скорее всего, достаточно быстро, если вы не запускаете его в цикле без каких-либо других значительных вычислений.
Во-вторых, я отправил уведомление из фоновой очереди и получил его в основной очереди, сравнив его с DispatchQueue:
Notification: 877 ms
DispatchQueue.sync: 871 ms
DispatchQueue.async: 867 ms
Здесь почти нет разницы.
Методология:
- Режим деблокирования
- айфон 5с
- iOS 10.3.2.
- Запросы всегда обрабатываются в основном потоке, независимо от того, из какого потока они отправляются.