Increasing Performance by Reducing Dynamic Dispatch
https://developer.apple.com/swift/blog/?id=39
Increasing Performance by Reducing Dynamic Dispatch
Like many other languages, Swift allows a class to override methods and properties declared in its superclasses. This means that the program has to determine at runtime which method or property is being referred to and then perform an indirect call or indirect access. This technique, called dynamic dispatch, increases language expressivity at the cost of a constant amount of runtime overhead for each indirect usage. In performance sensitive code such overhead is often undesirable. This blog post showcases three ways to improve performance by eliminating such dynamism: final, private, and Whole Module Optimization.
Consider the following example:
class ParticleModel {
var point = ( 0.0, 0.0 )
var velocity = 100.0
func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
var p = ParticleModel()
for i in stride(from: 0.0, through: 360, by: 1.0) {
p.update((i * sin(i), i), newV:i*1000)
}
As written, the compiler will emit a dynamically dispatched call to:
- Call update on p.
- Call updatePoint on p.
- Get the property point tuple of p.
- Get the property velocity of p.
This might not be what you would expect when looking at this code. The dynamic calls are necessary because a subclass of ParticleModel might override point or velocity with a computed property or override updatePoint() or update() with new implementations.
In Swift, dynamic dispatch calls are implemented by looking up a function from a method table and then performing an indirect call. This is slower than performing a direct call. Additionally, indirect calls also prevent many compiler optimizations, making the indirect call even more expensive. In performance critical code there are techniques you can use to restrict this dynamic behavior when it isn’t needed to improve performance.
Use final when you know that a declaration does not need to be overridden.
The final keyword is a restriction on a class, method, or property that indicates that the declaration cannot be overridden. This allows the compiler to safely elide dynamic dispatch indirection. For instance, in the following point and velocity will be accessed directly through a load from the object’s stored property and updatePoint() will be called via a direct function call. On the other hand, update() will still be called via dynamic dispatch, allowing for subclasses to override update() with customized functionality.
class ParticleModel {
final var point = ( x: 0.0, y: 0.0 )
final var velocity = 100.0
final func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
It is possible to mark an entire class as final by attaching the attribute to the class itself. This forbids subclassing the class, implying that all functions and properties of the class are final as well.
final class ParticleModel {
var point = ( x: 0.0, y: 0.0 )
var velocity = 100.0
// ...
}
Infer final on declarations referenced in one file by applying the private keyword.
Applying the private keyword to a declaration restricts the visibility of the declaration to the current file. This allows the compiler to find all potentially overriding declarations. The absence of any such overriding declarations enables the compiler to infer the final keyword automatically and remove indirect calls for methods and property accesses.
Assuming there is no class overriding ParticleModel in the current file, the compiler can replace all dynamically dispatched calls to private declarations with direct calls.
class ParticleModel {
private var point = ( x: 0.0, y: 0.0 )
private var velocity = 100.0
private func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
As in the previous example, point and velocity are accessed directly and updatePoint() is called directly. Again, update() will be invoked indirectly due to update() not being private.
Just like with final, it is possible to apply the private attribute to the class declaration itself causing the class to be private and thus all of the properties and methods of the class as well.
private class ParticleModel {
var point = ( x: 0.0, y: 0.0 )
var velocity = 100.0
// ...
}
Use Whole Module Optimization to infer final on internal declarations.
Declarations with internal access (the default if nothing is declared) are only visible within the module where they are declared. Because Swift normally compiles the files that make up a module separately, the compiler cannot ascertain whether or not an internal declaration is overridden in a different file. However, if Whole Module Optimization is enabled, all of the module is compiled together at the same time. This allows the compiler to make inferences about the entire module together and infer final on declarations with internal if there are no visible overrides.
Let’s go back to the original code snippet, this time adding some extra public keywords to ParticleModel.
public class ParticleModel {
var point = ( x: 0.0, y: 0.0 )
var velocity = 100.0
func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
point = newPoint
velocity = newVelocity
}
public func update(newP: (Double, Double), newV: Double) {
updatePoint(newP, newVelocity: newV)
}
}
var p = ParticleModel()
for i in stride(from: 0.0, through: times, by: 1.0) {
p.update((i * sin(i), i), newV:i*1000)
}
When compiling this snippet with Whole Module Optimization the compiler can infer final on the properties point, velocity, and the method call updatePoint(). In contrast, it can not be inferred that update() is final since update() has public access.
Increasing Performance by Reducing Dynamic Dispatch的更多相关文章
- Dynamic dispatch
Dynamic dispatch动态调度.动态分发 In computer science, dynamic dispatch is the process of selecting which im ...
- Dynamic dispatch mechanisms
Normally, in a typed language, the dispatch mechanism will be performed based on the type of the arg ...
- this inspection detects names that should resolved but don't. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases. Top-level and class-level items are sup
输入第一行代码:import logging;logging.basicConfig(level==logging.INFO) 提示:this inspection detects names tha ...
- 【PyCharm编辑器】之无法导入引用手动新建的包或类,报:This inspection detects names that should resolve but don't. Due to dynamic dispatch and duck typing, this is possible in a limited but useful number of cases.
一.现象描述 如下图所示,手动新建个类包calculator.py,想在test.py文件引用它,发现一直报红线,引用失败 Unresolved reference 'calculator' less ...
- swift -Dynamic Dispatch
These instructions perform dynamic lookup of class and generic methods. The class_method and super_m ...
- Only Link: What's the difference between dynamic dispatch and dynamic binding
http://stackoverflow.com/questions/20187587/what-is-the-difference-between-dynamic-dispatch-and-late ...
- 【Python】This inspection detects names that should resolve but don't. Due to dynamic dispatch and duck
情况一:导包import时发生错误,请参考这两位 https://blog.csdn.net/zhangyu4863/article/details/80212068https://www.cnblo ...
- [Angular] Increasing Performance by using Pipe
For example you make a function to get rating; getRating(score: number): string { let rating: string ...
- 唐巧的iOS技术博客选摘
1. 那些被遗漏的objective-c保留字:http://blog.devtang.com/blog/2013/04/29/the-missing-objc-keywords/ 2. 使用cr ...
随机推荐
- ETCD 添加节点报错 tocommit(2314438) is out of range [lastIndex(0)]. Was the raft log corrupted, truncated, or lost?
生产环境中一台ETCD节点宕机之后,添加新的节点的时候出现以下错误, tocommit(2314438) is out of range [lastIndex(0)]. Was the raft lo ...
- Java学习:集合双列Map
数据结构 数据结构: 数据结构_栈:先进后出 入口和出口在同一侧 数据结构_队列:先进先出 入口和出口在集合的两侧 数据结构_数组: 查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过 ...
- tomcat启动完成执行 某个方法 定时任务(Spring)
第一步引入接口: ServletContextListener @RestController @RequestMapping("/schedule") public class ...
- 解决IE下打印iframe时,页面比例变小的问题
$('#reportFrame')[0].contentWindow.printMyself();//主页面调用iframe里的打印方法 //reportFrame里的方法 function prin ...
- Mysql关键字Explain 性能优化神器
Explain工具介绍 使用EXPLAIN关键字可以模拟优化器执行SQL语句,分析查询语句或是结构的性能瓶颈.在select语句之前增加explaion关键字,MySQL会在查询上设置一个标记,执行查 ...
- 通过nginx部署前端代码实现前后端分离
实现前后端分离,可以让前后端独立开发.独立部署.独立单测,双方通过JSON进行数据交互. 对于前端开发人员来说,不用每次调试都需要启动或配置Java/Tomcat运行环境:对于后端开发人员来说 ,也不 ...
- day 28
目录 操作系统发展史 穿孔卡片 联机批处理系统 脱机批处理系统 多道技术(基于单核情况下研究) 单道 多道技术 并发与并行 进程 程序与进程 进程调度 先来先服务调度 短作业优先调度 时间片轮转法 分 ...
- Excel 批量导入Mysql(创建表-追加数据)
之前弄数据库的时候, 测试excel导mysql, 中间用pandas 处理后再入库. 直接上代码, 此种有真意, 尽在不言中. #!/usr/bin/env python # coding: ut ...
- Odoo XML中操作记录与函数
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826037.html 一:XML文件中定义记录 XML中定义记录: 每个<record>元素有 ...
- [加密]非对称加密STM32实现
转自:https://blog.csdn.net/kangerdong/article/details/82432701 把所有的准备工作都做完了以后,可以将加密算法移植到我们具体的项目中去了,在ST ...