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:

  1. Call update on p.
  2. Call updatePoint on p.
  3. Get the property point tuple of p.
  4. 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的更多相关文章

  1. Dynamic dispatch

    Dynamic dispatch动态调度.动态分发 In computer science, dynamic dispatch is the process of selecting which im ...

  2. Dynamic dispatch mechanisms

    Normally, in a typed language, the dispatch mechanism will be performed based on the type of the arg ...

  3. 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 ...

  4. 【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 ...

  5. swift -Dynamic Dispatch

    These instructions perform dynamic lookup of class and generic methods. The class_method and super_m ...

  6. 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 ...

  7. 【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 ...

  8. [Angular] Increasing Performance by using Pipe

    For example you make a function to get rating; getRating(score: number): string { let rating: string ...

  9. 唐巧的iOS技术博客选摘

    1. 那些被遗漏的objective-c保留字:http://blog.devtang.com/blog/2013/04/29/the-missing-objc-keywords/   2. 使用cr ...

随机推荐

  1. jmeter 获取总的线程数

    String threads="${__BeanShell(ctx.getThreadGroup().getNumThreads())}"; vars.put("thre ...

  2. R语言dataframe的常用操作总结

    前言:近段时间学习R语言用到最多的数据格式就是data.frame,现对data.frame常用操作进行总结,其中函数大部分来自dplyr包,该包由Hadley Wickham所作,主要用于数据的清洗 ...

  3. DDR3(3):写控制

    调取的 DDR3 控制器给用户端预留了接口,用于实现对该 IP 核的控制,本篇介绍一下 DDR3 IP核写.在生成 DDR3 IP 核的界面中,可以找到 User Guide 手册,DDR3 的使用将 ...

  4. SpringBoot:3.SpringBoot使用Spring-data-jpa实现数据库访问

    做Web开发,首先要能将数据渲染到网页中展示,其次是要获取数据库数据展示到视图层,在前面的文章SpringBoot整合Thymeleaf模板引擎渲染web视图,我们实现了从后端数据展示到视图层,那么下 ...

  5. 微软官方关于 Windows To Go 的常见问题

    Windows To Go:常见问题 2016/04/01 本文内容 什么是 Windows To Go? Windows To Go 是否依赖虚拟化? 哪些人员应该使用 Windows To Go? ...

  6. Docker 制作定制asp.netcore 的容器

    上文Windows docker k8s asp.net core的k8swebap镜像只是一个asp.net core程序,在实际生产中我们希望容器中还有一些其他程序,比如ssh 和telegraf ...

  7. 破解Charles4.2.7版本

    软件下载地址:请点我 密码:sats dmg软件解密密码是:xclient.info 激活方法 1.将 Charles.app 拖至 应用程序 文件夹 2.将 keygen.jar 拖至 桌面 3.打 ...

  8. <More Effective C#: 改善C#代码的50个有效方法>中文版翻译答疑

    最近, 有一本很赞的.NET技术书中文版出版了 - <More Effective C#: 改善C#代码的50个有效方法>.    从广州\西安\长沙\上海等各地.NET俱乐部都收到反馈, ...

  9. C#调用 kernel32.dll

    调用方法: private string mFileName; //INI文件名 public OneGanttINI(string pFileName) { this.mFileName = App ...

  10. SQL Server中临时表是在什么schema下的(转载)

    Specifying schema for temporary tables 问: I'm used to seeing temporary tables created with just the ...