【发布时间】:2015-07-11 04:09:03
【问题描述】:
以下代码将简单的值持有者映射到布尔值,在 Java 中的运行速度比 Swift 2 快 20 倍以上 - XCode 7 beta3、“Fastest, Aggressive Optimizations [-Ofast]”和“Fast, Whole Module Optimizations”开启.我可以在 Java 中获得超过 280M 的查找/秒,但在 Swift 中只有大约 10M。
当我在 Instruments 中查看它时,我发现大部分时间都进入了与映射查找相关的一对保留/释放调用。任何有关为什么会发生这种情况或解决方法的建议将不胜感激。
代码的结构是我真实代码的简化版本,它有一个更复杂的键类,还存储了其他类型(虽然布尔对我来说是一个实际案例)。另外,请注意,我使用单个可变键实例进行检索,以避免在循环内分配对象,根据我的测试,这在 Swift 中比不可变键更快。
编辑:我也尝试过切换到 NSMutableDictionary,但是当使用 Swift 对象作为键时,它似乎非常慢。
EDIT2:我尝试在 objc 中实现测试(它不会有可选的展开开销),它速度更快,但仍然比 Java 慢一个数量级......我将把这个例子设置为另一个问题,看看是否有人有想法。
EDIT3 - 回答。我在下面的答案中发布了我的结论和解决方法。
public final class MyKey : Hashable {
var xi : Int = 0
init( _ xi : Int ) { set( xi ) }
final func set( xi : Int) { self.xi = xi }
public final var hashValue: Int { return xi }
}
public func == (lhs: MyKey, rhs: MyKey) -> Bool {
if ( lhs === rhs ) { return true }
return lhs.xi==rhs.xi
}
...
var map = Dictionary<MyKey,Bool>()
let range = 2500
for x in 0...range { map[ MyKey(x) ] = true }
let runs = 10
for _ in 0...runs
{
let time = Time()
let reps = 10000
let key = MyKey(0)
for _ in 0...reps {
for x in 0...range {
key.set(x)
if ( map[ key ] == nil ) { XCTAssertTrue(false) }
}
}
print("rate=\(time.rate( reps*range )) lookups/s")
}
这里是对应的Java代码:
public class MyKey {
public int xi;
public MyKey( int xi ) { set( xi ); }
public void set( int xi) { this.xi = xi; }
@Override public int hashCode() { return xi; }
@Override
public boolean equals( Object o ) {
if ( o == this ) { return true; }
MyKey mk = (MyKey)o;
return mk.xi == this.xi;
}
}
...
Map<MyKey,Boolean> map = new HashMap<>();
int range = 2500;
for(int x=0; x<range; x++) { map.put( new MyKey(x), true ); }
int runs = 10;
for(int run=0; run<runs; run++)
{
Time time = new Time();
int reps = 10000;
MyKey buffer = new MyKey( 0 );
for (int it = 0; it < reps; it++) {
for (int x = 0; x < range; x++) {
buffer.set( x );
if ( map.get( buffer ) == null ) { Assert.assertTrue( false ); }
}
}
float rate = reps*range/time.s();
System.out.println( "rate = " + rate );
}
【问题讨论】:
-
您是否尝试将 MyKey 从类更改为结构或使用
indexForKey(key: Key)查找数据?结构具有不同的内存管理,indexForKey可能不同,因为它不返回对象,只是索引。 -
我正在尝试运行它,它显示错误未解析标识符
Time。 -
为了保持代码的重点,我没有包含我琐碎的计时器代码。我把它放在这里(Java 和 Swift):gist.github.com/patniemeyer/bf73e0e6f06a8b6de97e
-
使用 indexForKey() 的速度差不多。
-
“使用 indexForKey() 的速度差不多” 出于同样的原因 - 您每次都会生成一个额外的 Optional。
标签: performance swift swift2