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. Akka-CQRS(8)- CQRS Reader Actor 应用实例

    前面我们已经讨论了CQRS-Reader-Actor的基本工作原理,现在是时候在之前那个POS例子里进行实际的应用示范了. 假如我们有个业务系统也是在cassandra上的,那么reader就需要把从 ...

  2. 从nsurlsession、Alamofire到moya

    更好的理解(抽象).更少的构建(配置).更方便的表达(语言) 一.iOS系统的网络编程(DSL概念) ios缺省的网络编程只是给出了网络编程的基本概念: urlsession.request.resp ...

  3. 程序员不装x能行?先给登录来一个图形验证码!(canvas实现)

    细心的同学可以发现,现在很多网站当登录多次之后就会出现一个图形验证码,或是当提交表单.或点击获取手机验证码等等场景都会有图形验证码的出现. 那么图形验证码是为了解决什么问题而出现的呢? 什么是图形验证 ...

  4. ImportBeanDefinitionRegistrar接口实现bean动态注入

    借助ImportBeanDefinitionRegistrar接口实现bean的动态注入https://www.jianshu.com/p/2b993ced6a4c ImportBeanDefinit ...

  5. Ubuntu系统下基于docker部署Jenkins环境

    本文是在ubuntu环境下安装jenkins,jenkins运行在docker容器中, 至于docker如何安装,请参考https://www.cnblogs.com/xingyunqiu/p/115 ...

  6. 掌握算法&数据结构的正确方式

  7. java字符串常用方法总结(更新中..)

    一.String类 1.字符串拼接 String str1 = "abcd"; String str2 = "efgh"; System.out.println ...

  8. Java自学-类和对象 单例模式

    Java的饿汉式与懒汉式单例模式 LOL里有一个怪叫大龙GiantDragon,只有一只,所以该类,只能被实例化一次 步骤 1 : 单例模式 单例模式又叫做 Singleton模式,指的是一个类,在一 ...

  9. 【转载】C#如何获取DataTable中某列的数据类型

    在C#的数据表格DataTable的操作中,有时候因为业务需要,我们需要获取到DataTable所有列或者某一列的数据类型,此时我们可以通过DataTable中的Columns属性对象的DataTyp ...

  10. JavaSE02:第一个程序

    HelloWorld! 写第一个程序步骤 建一个文件,文件名改为HelloWorld.java 用文本编辑器打开并编写代码 public class HelloWorld{ public static ...