NSNotificationCenter vs delegation - which is fast

2019-01-24 04:43发布

问题:

I have read a lot about the pros and cons of each , and i know delegates are usually for one listener, and notifications are for many. The question is about performance.

I have read this : NSNotificationCenter vs delegation( using protocols )?

I am sending audio signals from mic, to another class by notification . i know that here i should use the delegate BUT my question is : does delegates will be faster ? because i can see i have some frame rate issue(decreased), and i would like to know if the cause could be the using of notification instead of delegate, or there is no relation ?

回答1:

Delegates come with less overhead and will therefore be executed much faster.

However, in general you should look on performance topics only there where they are likely to be an issue at all. For once-off tasks like sending a notification vs calling a delegate this should never be an issue. But when you plan to perform these in a loop with a variable (depending on data) number of intarations or for a number of data objects where you have fetched or received the data an cannot predict how many there will be - those are the situations where I would consider performance optimization.



回答2:

For those interested in performance I ran a simple test in swift using the XCTest framework's measureBlock API. The short answer is that if calling in a loop, the difference will be significant.

Here is the code used to test:

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()
    }
}

And the Test Cases:

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)
        }
   }
}

Results:
- Delegation:- - - - - - 0.957 seconds
- Notification Center: - 3.882 seconds

A Crappy Alternative I Tried

Other considerations are that the performance of NSNotificationCenter obviously may vary based on how many listeners there are for a given event, and the performance of the code executed by those listeners. Its also worth noting that NSNotificationCenter calls the notification listeners synchronously, and on the same thread on which postNotification was invoked, which can be a gotcha when first approaching NSNotificationCenter.

If you find yourself in a scenario, (as I have) where you need one to many communication, and high performance, you might consider simply implementing an array of delegates. But you need not bother, because the performance of this is actually the worst option.

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)
        }
   }
}

Final Results:
- Delegation:- - - - - - 0.957 seconds
- Notification Center: - 3.882 seconds
- Multiple Delegation: - 6.488 seconds



回答3:

Delegates are faster.

Your frame rate issue while recording is not due to delegates or notifications. It is because your are doing all your tasks on the main thread, which also renders the UI.



回答4:

NotificationCenter is fast enough.

First, I tested the synchronous case of posting and receiving a notification in the main thread, comparing it with a method call on self:

Method call: .036 ms
Notification: .13 ms

Each number is the worst case among 100 calls.

Since a notification is roughly a tenth of a millisecond slower even in this worst case, it's most likely fast enough, unless you run it in a loop without any other significant computation.

Second, I posted the notification from a background queue and received it in the main queue, comparing it with DispatchQueue:

Notification: 877 ms
DispatchQueue.sync: 871 ms
DispatchQueue.async: 867 ms

Here there's almost no difference.

Methodology: - Release mode - iPhone 5s - iOS 10.3.2. - Requests are always handled in the main thread, no matter which thread they're dispatched from.



回答5:

i know that here i should use the delegate BUT my question is : does delegates will be faster ?

It is easy: try and share the results!

The delegate when 1:1, point to point relationship can be faster than the 1:m publish and subscribe in any system.

Is it faster hard to answer, because it depends on environment. When aren't a lot of listeners and the publisher not need to search a lot for listeners, then should be similar performance, but when are a million of subscribers and need to search it, then can be a delay, frame rate decrease.



回答6:

A delegate will be faster than a notification but neither is necessarily what you need. For audio you should probably measure first. If you need something executed faster before updating the UI then you should look at moving some processing task to another thread via GCD dispatch or NSOperation.



回答7:

Calling the delegate is just a method invocation but when notifications are used there some more stuff should be done behind the scenes to deliver your notification. Considering this - delegate is a bit faster.

Realtime audio processing is a complex task and I tend to think that delegate's method call or sending a notification produces much more less overhead than your audio-processing code.

UPDATE

Considering performance issues you always should do measurements while trying different approaches.