Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift的第一步,在BST中分配小对象时的性能问题_Swift_Memory Management - Fatal编程技术网

Swift的第一步,在BST中分配小对象时的性能问题

Swift的第一步,在BST中分配小对象时的性能问题,swift,memory-management,Swift,Memory Management,在学习Swift 2.2的过程中,当我尝试分配许多小对象(基本上是262144个元素的BST)时,我面临着严重的性能下降。我目前的基准测试是一个Java 1.8.0_74编译版,它是我几年前编写的一个旧剪报,在我的2012款Retina Macbook Pro上,执行时间为59秒(59036178微秒)。我可以通过仪器观察到的问题是,我每次迭代都会得到几十个swift_retain_和swift_release。不知道如何避免它们: import Foundation import Darwin

在学习Swift 2.2的过程中,当我尝试分配许多小对象(基本上是262144个元素的BST)时,我面临着严重的性能下降。我目前的基准测试是一个Java 1.8.0_74编译版,它是我几年前编写的一个旧剪报,在我的2012款Retina Macbook Pro上,执行时间为59秒(59036178微秒)。我可以通过仪器观察到的问题是,我每次迭代都会得到几十个swift_retain_和swift_release。不知道如何避免它们:

import Foundation
import Darwin;

import Foundation

public class BinarySearchTree<T : Comparable> {
    private var _value : T?;

    private var _leftTree : BinarySearchTree<T>?;
    private var _rightTree : BinarySearchTree<T>?;

    public init(value : T) {
        _value = value;
    }

    var value : T? {
        get {
            return self._value;
        }
        set {
            self._value = newValue;
        }
    }

    var leftTree : BinarySearchTree<T>? {
        get {
            return self._leftTree;
        }
        set {
            self._leftTree = newValue;
        }
    }

    var rightTree : BinarySearchTree<T>? {
        get {
            return self._rightTree;
        }
        set {
            self._rightTree = newValue;
        }
    }

    public func add(newValue : T) -> BinarySearchTree<T> {
        var navigator : BinarySearchTree<T>?;
        var subtree : BinarySearchTree<T>?;

        var done : Bool?;

        done = false;
        navigator = self;

        while (!done!) {
            if (newValue < navigator?.value) {
                subtree = navigator?.leftTree;
                if (subtree != nil) {
                    navigator = subtree;
                } else {
                    let newNode = BinarySearchTree<T>(value: newValue);
                    navigator!.leftTree = newNode;
                    done = true;
                }
            } else if (newValue > navigator?.value) {
                subtree = navigator?.rightTree;
                if (subtree != nil) {
                    navigator = subtree;
                } else {
                    let newNode = BinarySearchTree<T>(value: newValue);
                    navigator?.rightTree = newNode;
                    done = true;
                }
            } else {
                done = true;
            }
        }
        return self;
    }
} /* cut remove/search methods */
<代码>导入基础 输入达尔文; 进口基金会 公共类二进制搜索树{ 私有var_值:T?; 私有var_leftTree:BinarySearchTree?; 私有var_rightree:BinarySearchTree?; 公共初始化(值:T){ _价值=价值; } var值:T{ 得到{ 返回自我价值; } 设置{ 自我价值=新价值; } } var leftTree:BinarySearchTree{ 得到{ 返回自我。_leftTree; } 设置{ self.\u leftTree=newValue; } } var rightTree:BinarySearchTree{ 得到{ 回归自我; } 设置{ self._rightree=newValue; } } public func add(newValue:T)->二进制搜索树{ 变量导航器:BinarySearchTree?; 变量子树:二进制搜索树?; var-done:Bool?; 完成=错误; 导航器=自我; 而(!完成!){ if(newValuenavigator?.value){ 子树=导航器?.rightTree; if(子树!=nil){ 导航器=子树; }否则{ 让newNode=BinarySearchTree(值:newValue); navigator?.rightTree=newNode; 完成=正确; } }否则{ 完成=正确; } } 回归自我; } }/*剪切删除/搜索方法*/ 这是我为测试运行编写的测试代码

let count : Int32 = 262144;
let base : Int32 = 65536;
let target : Int32 = count + 1;

var info = mach_timebase_info(numer:0, denom:0);
var timebase = mach_timebase_info(&info);
let numer = UInt64(info.numer);
let denom = UInt64(info.denom);
let norm = UInt64(numer/denom);

let check1 = (mach_absolute_time() * norm);

var root = BinarySearchTree<Int32>(value:base);

for var loop in 0 ... count-1 {
    if (loop % 1000 == 0) {
        print(loop);
    }
    root = root.add(loop);
}

let check2 = (mach_absolute_time() * norm);
print("Creation phase microseconds: [" + String((check2 - check1) / 1000) + "]");
let count:Int32=262144;
let base:Int32=65536;
让目标:Int32=count+1;
var info=马赫时基信息(数字:0,数字:0);
var时基=马赫时基信息(&info);
设numer=UInt64(info.numer);
设denom=UInt64(info.denom);
设norm=UInt64(数值/名称);
让检查1=(马赫绝对时间()*标准);
var root=BinarySearchTree(值:base);
对于0中的var循环。。。计数-1{
if(循环%1000==0){
打印(循环);
}
root=root.add(循环);
}
让检查2=(马赫绝对时间()*标准);
打印(“创建阶段微秒:[“+字符串((检查2-检查1)/1000)+”];

我尝试搜索特定的swift释放/保留问题,但运气不佳,我不确定如何继续。谢谢大家

我简化了您的代码,删除了一些
选项
和getter/setter,因为它们是不必要的,可能会导致代码变慢

我分析了您的代码和我的代码,并在相同的随机元素数据集上得到了这个结果:

1000个要素:

您的:创建阶段微秒:[28680771]

矿山:创建阶段微秒:[8564279]

10000个要素:

您的:创建阶段微秒:[426233689]

矿山:创建阶段微秒:[126725800]

这是我的密码:

public class BinarySearchTree2<T : Comparable> {
  public init(value : T) {
    self.value = value
  }

  var value : T
  var leftTree : BinarySearchTree2<T>?
  var rightTree : BinarySearchTree2<T>?

  public func add(newValue : T) -> BinarySearchTree2<T> {
    var navigator = self

    while (true) {
      if (newValue < navigator.value) {
        guard let subtree = navigator.leftTree else {
          navigator.leftTree = BinarySearchTree2<T>(value: newValue)
          break
        }
        navigator = subtree
        continue
      }
      if (newValue > navigator.value) {
        guard let subtree = navigator.rightTree else {
          navigator.rightTree = BinarySearchTree2<T>(value: newValue)
          break
        }
        navigator = subtree
        continue
      }
      break
    }
    return self
  }
} /* cut remove/search methods */

正如您所注意到的,问题是保留/释放(虽然它不是真的,但是保留/释放与Umm的力量相比是微不足道的……我们将在最后到达那里)。这实际上与分配无关。您没有分配额外的对象,您只是简单地保留它们,然后释放它们。我将从Kenneth的代码开始,它优化了原始版本中的许多性能问题,但仍然存在这个问题。(我不考虑递归代码,因为它在您当前的用例中崩溃。不过,它确实避免了一些冗余保留。)

值得一提的是,Kenneth的代码是好的,通常是您应该做事情的方式(随着我们的讨论,您将看到更多)

第一个注意事项:当您提到AST时,这是针对ObjC的,而不是Swift。Swift的标志只是
-O
。您还需要
-整个模块优化
,但这并没有真正的帮助

还有一件小事,我们就要开始了。随时标记课程
final
。这样可以确保没有动态调度。与保留/发布相比,这没什么大不了的,但是,嘿,简单一点

30%的折扣听起来好吗? 好的,现在是一个大的,这是一个骗局。我发现,通过重写以下内容,我可以减少约30%的时间(完全导入从~6分钟到~4分钟):

guard let subtree = navigator.leftTree else {
    navigator.leftTree = BinarySearchTree<T>(value: newValue)
    break
}
navigator = subtree
continue
这是一件需要非常小心的事情。事实证明,在这种情况下速度更快,但在其他输入中可能没有那么快。对于优化器的更改,这可能没有那么快(SIL生成有点奇怪,我怀疑这实际上可能是一个错误,因为在第二种情况下,它似乎双重保留了
navigator
,但只有在
if
成功之后)。但目前看来确实要快一些。(编辑:Swift团队对这一发现感到惊讶,现在有人反对这一发现。不要指望这在将来奏效。)

85%怎么样?听起来怎么样? 但是就像你说的,我们不能用结构避免所有这些吗?但如果我们每次触摸整棵树都要复制它,那就太贵了。当然,通过使用类似于写时拷贝的数组,我们可以极大地改进这一点。但是牛很漂亮
guard let subtree = navigator.leftTree else {
    navigator.leftTree = BinarySearchTree<T>(value: newValue)
    break
}
navigator = subtree
continue
let subtree = navigator.leftTree
if subtree == nil {
    navigator.leftTree = BinarySearchTree(value: newValue)
    break
}
navigator = subtree!
continue
private struct Node<Element: Comparable> {
    let value: Element
    var leftIndex = -1 // Ugly, but ~25% faster than using Int? in my tests
    var rightIndex = -1
    init(_ value: Element) { self.value = value }
}

// This works exactly the same if you make it a `final class`. Your choice.
public struct BinarySearchTree<Element: Comparable> {
    private var storage: [Node<Element>] = []

    init(value: Element) { storage.append(Node(value)) }

    public mutating func add(newValue: Element) {
        if storage.isEmpty {
            storage.append(Node(newValue))
        }

        var index = 0

        while (true) {
            let node = storage[index]
            if (newValue < node.value) {
                if node.leftIndex < 0 {
                    storage.append(Node(newValue))
                    storage[index].leftIndex = storage.count - 1 // Don't use node here; remember value types!
                    break
                }
                index = node.leftIndex
                continue
            } else if (newValue > node.value) {
                if node.rightIndex < 0 {
                    storage.append(Node(newValue))
                    storage[index].rightIndex = storage.count - 1
                    break
                }
                index = node.rightIndex
                continue
            } else {
                break
            }
        }
    }
}
var values = Array(0 ... count - 1)
values.shuffleInPlace()
for (loop, value) in values.enumerate() {
    if (loop % 1000 == 0) {
        print(loop)
    }
    root.add(value)
}