【问题标题】:Really fast addition of Strings in swift快速添加字符串
【发布时间】:2016-11-27 19:57:04
【问题描述】:

以下代码显示了构建电子表格的两种方法: 通过使用:

str = str + "\(number) ; "

str.append("\(number)");

两者都非常慢,因为我认为它们丢弃了两个字符串并制作了第三个字符串,这是前两个字符串的串联。 现在,如果我重复这个操作数十万次来增加一个电子表格......这会产生很多分配。

例如,以下代码在我的 MacBook Pro 2016 上执行需要 11 秒:

    let start = Date()
    var str = "";

    for i in 0 ..< 86400
    {
        for j in 0 ..< 80
        {
//          Use either one, no difference
//          str = str + "\(Double(j) * 1.23456789086756 + Double(i)) ; "
            str.append("\(Double(j) * 1.23456789086756 + Double(i)) ; ");
        }

        str.append("\n")
    }

    let duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
    print(duration);

我怎样才能解决这个问题而不必自己将双打转换为字符串?我已经坚持了 3 天...我的编程技能非常有限,您可能从上面的代码中可以看到...

我试过了:

var str = NSMutableString(capacity: 86400*80*20);

但是编译器告诉我:

Variable 'str' was never mutated; consider changing to 'let' constant

尽管

str.append("\(Double(j) * 1.23456789086756 + Double(i)) ; ");

显然,调用 append 不会改变字符串...

【问题讨论】:

  • 我不认为 str.appendDouble 很慢...调用一行嵌套代码 86400 * 80 = 6,912,000 次会让任何事情看起来都很慢。
  • 是的,我知道。这是因为我让一个字符串增长了 6,912,000...所以我进行了复制、分配等...删除了该部分(不添加,只需创建一个新字符串),看看它运行的速度有多快(0.043 秒)。分配是这里的杀手锏。所以我尝试将其设为具有容量的 NSMutableString,但显然,在 swift3 中追加副本而不是变异。
  • 启用优化后,“不添加,只创建一个新字符串”代码将被删除。您的代码附加常量字符串需要多长时间,例如 str.append("1.23456789086756 ; ")
  • 我猜你想把它写到文件或其他东西中。如果是这样,只需创建一个流并将值写入流。它只会将值附加到当前流位置,您不必担心 str.append。如果这是最终计算的一部分,您可能还会发现将 * 替换为 + 会更快 - 尽管现在不确定,但必须对其进行测试
  • 似乎有问题的部分是从DoubleString 的转换,其他一切在我的测试中都非常快。

标签: swift string optimization concatenation


【解决方案1】:

我尝试将它写入数组,但限制因素似乎是将双精度数转换为字符串。

下面的代码在我的空气中需要 13 秒左右

这样做

arr[i][j] = "1.23456789086756"

将执行时间降低到 2 秒,因此将 Double 转换为 String 需要 11 秒。您可能可以通过编写自己的转换例程来节省一些时间,但这似乎是一个限制因素。我尝试使用内存流,这似乎更慢。

 var start = Date()

        var arr = Array(repeating: Array(repeating: "1.23456789086756", count: 80), count: 86400 )
        var duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
        print(duration); //0.007
        start = Date()

        var a = 1.23456789086756

        for i in 0 ..< 86400
        {
            for j in 0 ..< 80
            {
                arr[i][j] = "\(a)" // "1.23456789086756" //String(a)
            }
        }

        duration = Date().timeIntervalSinceReferenceDate - start.timeIntervalSinceReferenceDate;
        print(duration); //13.46 or 2.3 with the string

【讨论】:

  • +1 - 谢谢,即使我不想填充数组。我会再等一会,如果没有更多回复,我会接受你的作为最接近问题的答案。
  • @Adeline 削减它的一种方法是并行化例程 - 可能很明显但提到它以防万一,在这种情况下很简单。如果你有一个四核,你可以期望它减少到几秒钟
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-24
  • 1970-01-01
  • 2019-04-30
  • 2013-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多