可可触摸编程。内环中的KVO / KVC超慢。我如何加快速度?

时间:2022-03-30 07:11:47

I've become a huge fan of KVO/KVC. I love the way it keeps my MVC architecture clean. However I am not in love with the huge performance hit I incur when I use KVO within the inner rendering loop of the 3D rendering app I'm designing where messages will fire at 60 times per second for each object under observation - potentially hundreds.

我已成为KVO / KVC的忠实粉丝。我喜欢它保持我的MVC架构清洁的方式。然而,当我在3D渲染应用程序的内部渲染循环中使用KVO时,我并不喜欢我所遇到的巨大性能损失,我正在设计消息将以每秒60次的速度为每个观察对象发射 - 可能有数百个。

What are the tips and tricks for speeding up KVO? Specifically, I am observing a scalar value - not an object - so perhaps the wrapping/unwrapping is killing me. I am also setting up and tearing down observation

加速KVO有哪些提示和技巧?具体来说,我正在观察一个标量值 - 而不是一个对象 - 所以包裹/解包可能会让我感到害怕。我也在设置和拆除观察

[foo addObserver:bar forKeyPath:@"fooKey" options:0 context:NULL];
[foo removeObserver:bar forKeyPath:@"fooKey"];

within the inner loop. Perhaps I'm taking a hit for that.

在内循环内。也许我正在受到打击。

I really, really, want to keep the huge flexibility KVO provides me. Any speed freaks out there who can lend a hand?

我真的非常想保持KVO为我提供的巨大灵活性。那些可以伸出援手的速度怪异吗?

Cheers, Doug

1 个解决方案

#1


Objective-C's message dispatch and other features are tuned and pretty fast for what they provide, but they still don't approach the potential of tuned C for computational tasks:

Objective-C的消息调度和其他功能针对它们提供的内容进行了调整和快速,但是它们仍然没有为计算任务接近调优C的潜力:

NSNumber *a = [NSNumber numberWithIntegerValue:(b.integerValue + c.integerValue)];

is way slower than:

比以下慢:

NSInteger a = b + c;

and nobody actually does math on objects in Objective-C for that reason (well that and the syntax is awful).

并且由于这个原因,没有人真正对Objective-C中的对象进行数学运算(那个和语法很糟糕)。

The power of Objective-C is that you have a nice expressive message based object system where you can throw away the expensive bits and use pure C when you need to. KVO is one of the expensive bits. I love KVO, I use it all the time. It is computationally expensive, especially when you have lots of observed objects.

Objective-C的强大之处在于你有一个很好的基于表达式消息的对象系统,你可以扔掉昂贵的位并在需要时使用纯C。 KVO是昂贵的比特之一。我喜欢KVO,我一直都在使用它。它的计算成本很高,特别是当你有很多被观察的物体时。

An inner loop is that small bit of code you run over and over, anything thing there will be done over and over. It is the place where you should be eliminating OOP features if need be, where you should not be allocating memory, where you should be considering replacing method calls with static inline functions. Even if you somehow manage to get acceptable performance in your rendering loop, it will be much lower performance than if you got all that expensive notification and dispatch logic out of there.

内部循环是你反复运行的一小段代码,任何事情都会反复进行。如果需要,你应该在那里消除OOP功能的地方,你不应该在那里分配内存,你应该考虑用静态内联函数替换方法调用。即使你以某种方式设法在渲染循环中获得可接受的性能,它的性能也会比你从那里获得所有昂贵的通知和调度逻辑要低得多。

If you really want to try to keep it going with KVO here are a few things you can try to make things go faster:

如果你真的想让它继续使用KVO这里有一些你可以试着让事情变得更快的事情:

  1. Switch from automatic to manual KVO in your objects. This may allow you to reduce spurious notifications
  2. 在对象中从自动切换到手动KVO。这可能允许您减少虚假通知

  3. Aggregate updates: If your intermediate values over some time interval are not relevant, and you can defer for some amount of time (like the next animation frame) don't post the change, mark that the change needs to posted and wait for a the relevent timer to go off, you might get to avoid a bunch of short lived intermediary updates. You might also use some sort of proxy to aggregate related changes between multiple objects.
  4. 聚合更新:如果某个时间间隔内的中间值不相关,并且您可以推迟一段时间(如下一个动画帧),请不要发布更改,请标记更改需要发布并等待相关计时器关闭,你可能会避免一堆短暂的中介更新。您还可以使用某种代理来聚合多个对象之间的相关更改。

  5. Merge observable properties: If you have a large number of properties in one type of object that might change you may be better off making a single "hasChanges" property observe and having the the observer query the properties.
  6. 合并可观察属性:如果在一种类型的对象中有大量属性可能会发生变化,那么最好使用一个“hasChanges”属性观察并让观察者查询属性。

#1


Objective-C's message dispatch and other features are tuned and pretty fast for what they provide, but they still don't approach the potential of tuned C for computational tasks:

Objective-C的消息调度和其他功能针对它们提供的内容进行了调整和快速,但是它们仍然没有为计算任务接近调优C的潜力:

NSNumber *a = [NSNumber numberWithIntegerValue:(b.integerValue + c.integerValue)];

is way slower than:

比以下慢:

NSInteger a = b + c;

and nobody actually does math on objects in Objective-C for that reason (well that and the syntax is awful).

并且由于这个原因,没有人真正对Objective-C中的对象进行数学运算(那个和语法很糟糕)。

The power of Objective-C is that you have a nice expressive message based object system where you can throw away the expensive bits and use pure C when you need to. KVO is one of the expensive bits. I love KVO, I use it all the time. It is computationally expensive, especially when you have lots of observed objects.

Objective-C的强大之处在于你有一个很好的基于表达式消息的对象系统,你可以扔掉昂贵的位并在需要时使用纯C。 KVO是昂贵的比特之一。我喜欢KVO,我一直都在使用它。它的计算成本很高,特别是当你有很多被观察的物体时。

An inner loop is that small bit of code you run over and over, anything thing there will be done over and over. It is the place where you should be eliminating OOP features if need be, where you should not be allocating memory, where you should be considering replacing method calls with static inline functions. Even if you somehow manage to get acceptable performance in your rendering loop, it will be much lower performance than if you got all that expensive notification and dispatch logic out of there.

内部循环是你反复运行的一小段代码,任何事情都会反复进行。如果需要,你应该在那里消除OOP功能的地方,你不应该在那里分配内存,你应该考虑用静态内联函数替换方法调用。即使你以某种方式设法在渲染循环中获得可接受的性能,它的性能也会比你从那里获得所有昂贵的通知和调度逻辑要低得多。

If you really want to try to keep it going with KVO here are a few things you can try to make things go faster:

如果你真的想让它继续使用KVO这里有一些你可以试着让事情变得更快的事情:

  1. Switch from automatic to manual KVO in your objects. This may allow you to reduce spurious notifications
  2. 在对象中从自动切换到手动KVO。这可能允许您减少虚假通知

  3. Aggregate updates: If your intermediate values over some time interval are not relevant, and you can defer for some amount of time (like the next animation frame) don't post the change, mark that the change needs to posted and wait for a the relevent timer to go off, you might get to avoid a bunch of short lived intermediary updates. You might also use some sort of proxy to aggregate related changes between multiple objects.
  4. 聚合更新:如果某个时间间隔内的中间值不相关,并且您可以推迟一段时间(如下一个动画帧),请不要发布更改,请标记更改需要发布并等待相关计时器关闭,你可能会避免一堆短暂的中介更新。您还可以使用某种代理来聚合多个对象之间的相关更改。

  5. Merge observable properties: If you have a large number of properties in one type of object that might change you may be better off making a single "hasChanges" property observe and having the the observer query the properties.
  6. 合并可观察属性:如果在一种类型的对象中有大量属性可能会发生变化,那么最好使用一个“hasChanges”属性观察并让观察者查询属性。