当前位置: 首页 > 知识库问答 >
问题:

斯威夫特的字典即使有-ofast也很慢

杜霍英
2023-03-14

我正在使用Swift中的dictionary实现实质上是一个缓存。演出远未达到我的预期。我读过一些其他问题,例如关于数组排序的问题,它似乎暗示-ofast是答案(如果您准备接受它带来的更改)。但是,即使在编译-ofast时,性能也比其他语言差。我使用的是Swift 1.0版(Swift-600.0.34.4.8)。

下面是一个简单的例子来说明这个问题:

import Foundation

class Holder {
    var dictionary = Dictionary<Int, Int>()

    func store(#key: Int, value: Int) {
        dictionary[key] = value
    }
}

let holder = Holder()

let items = 5000

for (var i: Int = 0; i < 5000; i++) {
    holder.store(key: i, value: i)
}

使用-o3编译时,运行时间超过两秒:

xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -O3 Test.swift && time ./Test

real    0m2.295s
user    0m2.176s
sys     0m0.117s
xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -Ofast Test.swift && time ./Test

real    0m0.602s
user    0m0.484s
sys     0m0.117s

相比之下,这个Java实现:

import java.util.Map;
import java.util.HashMap;

public class Test {
    public static void main(String[] args) {
        Holder holder = new Holder();
        int items = 5000;
        for (int i = 0; i < items; i++) {
            holder.store(i, i);
        }
    }
}

class Holder {
    private final Map<Integer, Integer> map = new HashMap<Integer, Integer>();

    public void store(Integer key, Integer value) {
        map.put(key, value);
    }
}

又快了6倍:

javac Test.java && time java Test

real    0m0.096s
user    0m0.088s
sys     0m0.021s

难道仅仅是复制dictionary并将其存储在holder实例中的成本导致Swift如此糟糕吗?删除holder并直接访问Dictionary将提示它是。

import Foundation

var dictionary = Dictionary<Int, Int>()

let items = 5000

for (var i: Int = 0; i < 5000; i++) {
    dictionary[i] = i
}
$ xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -O3 NoHolder.swift && time ./NoHolder

real    0m0.011s
user    0m0.009s
sys     0m0.002s

$ xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) -Ofast NoHolder.swift && time ./NoHolder

real    0m0.011s
user    0m0.007s
sys     0m0.003s

虽然它提供了一个(希望)有趣的数据点,但在我的情况下直接访问字典是不可能的。我还能做些什么来接近Swift目前的表现水平吗?

共有1个答案

薄兴昌
2023-03-14

是贝塔博士。

我认为现在的答案是Swift已经进入测试版,工具也已经进入测试版,还有很多优化工作还没有完成。在Obj-C中复制您的“holder”类示例表明,即使它在相同的-ofast级别上也要快一些。

@import Foundation;

@interface Holder : NSObject

@property NSMutableDictionary *dictionary;
- (void)storeValue:(NSInteger)value forKey:(NSString *)key;

@end

@implementation Holder

- (instancetype)init {
   self = [self initWithDict];
    return self;
}


- (instancetype)initWithDict {
    if (!self) {
        self = [super init];
        _dictionary = [NSMutableDictionary dictionary];
    }

    return self;
}

- (void)storeValue:(NSInteger)value forKey:(NSString *)key {
    [self.dictionary setValue:@(value) forKey:key];
}

@end

int main(int argc, const char * argv[]) {

    Holder *holder = [Holder new];

    for (NSInteger i = 0; i < 5000; i++) {
        [holder storeValue:i forKey:[NSString stringWithFormat:@"%ld", i]];
    }

}

Obj-C很快就出了门。

time ./loop 

    real    0m0.013s
    user    0m0.006s
    sys     0m0.003s
OS-X-Dos-Equis:~ joshwisenbaker$ wc -l objc.txt 
     159 objc.txt
OS-X-Dos-Equis:~ joshwisenbaker$ wc -l oFast.txt 
    3749 oFast.txt

因此,另一个有趣的变化是在类定义上使用了@final修饰。如果您知道您的类永远不会被子类化,那么请尝试添加以下关键字:@final class holder

正如您所看到的,它还以同样的方式使编译时的性能正常化。

OS-X-Dos-Equis:~ joshwisenbaker$ swift -sdk $(xcrun --show-sdk-path --sdk macosx) -Ofast bench.swift && time ./bench

real    0m0.013s
user    0m0.007s
sys     0m0.003s

即使只使用-O3@final也能发挥神奇的作用。

OS-X-Dos-Equis:~ joshwisenbaker$ swift -sdk $(xcrun --show-sdk-path --sdk macosx) -O3  bench.swift && time ./bench

real    0m0.015s
user    0m0.009s
sys 0m0.003s
 类似资料:
  • 问题内容: 我正在学习快速,并试图理解字典。我已经习惯了PHP,您可能会在其中编写以下内容… 在此示例中,将按以下顺序输出值:1、2、3 我的快速代码看起来像这样… 但是,值以意外的顺序出现。我可以做些干净的事情来保持值的创建顺序,还是不能对字典进行快速排序? 问题答案: 正如已经回答的那样,词典的要点是未排序。Swift(和Objective-C)中有三种类型的集合 数组是项目的有序列表。当项目

  • 在使用swift教程时,我开始编写一个自定义的方法来检查给定的是否为素数。 在编写完它之后,我意识到它工作正常,但发现在一些相当大的数字上执行有点慢(仍然比)。 所以我用objc编写了相同的代码,并且代码的执行速度快得多(是66倍)。 以下是swift代码: 和对象代码: 在中: 这就产生了:

  • 问题内容: 为了在使用Swift时与C API集成,我需要使用sizeof函数。在C语言中,这很容易。在Swift中,我处于类型错误的迷宫中。 我有以下代码: 第二行显示错误“’NSNumber’不是’T.Type’的子类型”。为什么会这样,我该如何解决? 问题答案: 使用sizeof如下: 使用类型作为参数。 如果您想要变量的大小,可以将该字段传递给。 像这样: 或更简单地说(由user1020

  • 问题内容: 我一直在尝试实现单例,以用作我从网络上传到我的iOS应用的照片的缓存。我在下面的代码中附加了三个变体。我试图使版本2正常工作,但是它导致了我不理解的编译器错误,并希望就我做错的事情寻求帮助。变体1进行缓存,但我不喜欢使用全局变量。变体3并没有进行实际的缓存,我相信这是因为我在赋给var ic = ....的赋值中获得了副本,对吗? 任何反馈和见解将不胜感激。 谢谢Zvi 问题答案: 标

  • 问题内容: 要找到第一个,请使用: 我如何找到第二次出现? 问题答案: 项目清单 您可以按照以下步骤在剩余的数组切片中再次搜索元素的索引: 编辑/更新: Xcode 11•Swift 5.1或更高版本 测试:

  • 问题内容: 什么之间的区别,以及何时该使用的呢? 例如,在Python中,如果我想打印字典,我只是,但是现在有2个其他选项。我应该如何以及何时使用它们? 问题答案: 一些区别: vs : 调试应用程序时,该功能在Xcode控制台中打印消息。 这是Swift 2中已删除且不再使用的变体。如果看到正在使用的旧代码,则可以安全地将其替换为。 回到Swift 1.x,没有在打印字符串的末尾添加换行符,而是