Swift str=str+&引用;abc";慢于str=";abc"+;str?

Swift str=str+&引用;abc";慢于str=";abc"+;str?,swift,string,multithreading,grand-central-dispatch,Swift,String,Multithreading,Grand Central Dispatch,你能相信吗? 我有一个这样的循环(请原谅任何错误,我必须大量编辑大量信息和变量名,相信我,它是有效的) …旧示例已编辑,请参见下面的代码 如果我将中间的str=“Blah\(odat.count)”+str类型行更改为str=str+“Blah\(odat.count)”用户界面将停止运行,我得到了色轮。NSTextField确实到达第一个self.display.string…,但随后冻结 我是一个多线程新手,所以请随意更正我的方法。希望我想要的东西很清楚 我不得不承认,工作版本也有点口吃,但

你能相信吗? 我有一个这样的循环(请原谅任何错误,我必须大量编辑大量信息和变量名,相信我,它是有效的)

…旧示例已编辑,请参见下面的代码

如果我将中间的
str=“Blah\(odat.count)”+str
类型行更改为
str=str+“Blah\(odat.count)”
用户界面将停止运行,我得到了色轮。NSTextField确实到达第一个
self.display.string…
,但随后冻结

我是一个多线程新手,所以请随意更正我的方法。希望我想要的东西很清楚

我不得不承认,工作版本也有点口吃,但从来没有真正冻结。 典型值为n=70,var3=7

编辑:

下面是一个完全有效的示例。只需链接文本视图、进度条和按钮即可。尝试在主要功能之间切换

//
//  Controllers.swift
//
//

import Cocoa

class MainController: NSObject {

    @IBOutlet var display: NSTextView!
    @IBOutlet weak var prog: NSProgressIndicator!

    @IBAction func go1(sender: AnyObject) {
        theRoutine(70)
    }

    @IBAction func go2(sender: AnyObject) {
        theRoutine(50)
    }

    class SomeClass {
        var x: Int
        var y: Int
        var p: Double

        init?(size: Int, pro: Double) {
            x = size
            y = size
            p = pro
        }
    }

    func theRoutine(n: Int) {
        prog.hidden = false
        prog.doubleValue = 0
        prog.maxValue = 7 * 40
        let priority = DISPATCH_QUEUE_PRIORITY_HIGH
        dispatch_async(dispatch_get_global_queue(priority, 0)) {
            self.theFunc(n, var1: 0.06, var2: 0.06, var3: 7)
            self.theFunc(n, var1: 0.1*log(Double(n))/Double(n), var2: 0.3*log(Double(n))/Double(n), var3: 7)
            dispatch_async(dispatch_get_main_queue()) {
                self.prog.hidden = true
                self.appOut("done!")
            }
        }
    }

    //This doesn't
//  func theFunc(n: Int, var1: Double, var2: Double, var3: Int) {
//      var m: AnEnum
//      var gra: SomeClass
//      var p = var1
//      for _ in 0...(var3 - 1) {
//          var str  = "blah \(p)\n"
//          for _ in 1...20 {
//              gra = SomeClass(size: n, pro: p)!
//              m = self.doSomething(gra)
//              switch m {
//              case .First(let dat):
//                  str = str + "Blah:\n\(self.arrayF(dat, transform: {"blah\($0)blah\($1)=blah"}))" + "\n\n" + str
//              case .Second(let odat):
//                  str = str + "Blah\(odat.count) blah\(self.arrayF(odat, transform: {"bl\($1)"}))" + "\n\n" + str
//              }
//              dispatch_async(dispatch_get_main_queue()) {
//                  self.prog.incrementBy(1)
//              }
//          }
//          dispatch_async(dispatch_get_main_queue()) {
//              // update some UI
//              self.display.string = str + "\n" + (self.display.string ?? "")
//          }
//          p += var2
//      }
//  }

    //This works
    func theFunc(n: Int, var1: Double, var2: Double, var3: Int) {
        var m: AnEnum
        var gra: SomeClass
        var p = var1
        for _ in 0...(var3 - 1) {
            var str  = "blah \(p)\n"
            for _ in 1...20 {
                gra = SomeClass(size: n, pro: p)!
                m = self.doSomething(gra)
                switch m {
                case .First(let dat):
                    str = "Blah:\n\(self.arrayF(dat, transform: {"blah\($0)blah\($1)=blah"}))" + "\n\n" + str
                case .Second(let odat):
                    str = "Blah\(odat.count) blah\(self.arrayF(odat, transform: {"bl\($1)"}))" + "\n\n" + str
                }
                dispatch_async(dispatch_get_main_queue()) {
                    self.prog.incrementBy(1)
                }
            }
            dispatch_async(dispatch_get_main_queue()) {
                // update some UI
                self.display.string = str + "\n" + (self.display.string ?? "")
            }
            p += var2
        }
    }

    func doSomething(G: SomeClass) -> AnEnum {
        usleep(30000)
        if drand48() <= G.p {
            return AnEnum.First([0, 0])
        } else {
            return AnEnum.Second([1, 1, 1])
        }
    }

    enum AnEnum {
        case First([Int])
        case Second([Int])
    }

    func appOut(out: String?) {
        if out != nil {
            display.string = out! + "\n\n" + (display.string ?? "")
        }
    }

    func arrayF(array: [Int], transform: (index: Int, value: Int) -> String) -> String {
        let arr = Array(0...(array.count - 1))
        return "[\(arr.map{transform(index: $0, value: array[$0])}.joinWithSeparator(", "))]"
    }
}
//
//斯威夫特
//
//
进口可可
类MainController:NSObject{
@IBOUTLE var显示:NSTextView!
@IBOUTLE弱var程序:程序指示器!
@iAction func go1(发送方:任意对象){
theRoutine(70)
}
@iAction func go2(发送方:AnyObject){
theRoutine(50)
}
上课{
变量x:Int
变量y:Int
var p:双
初始?(大小:Int,pro:Double){
x=尺寸
y=尺寸
p=pro
}
}
函数路径(n:Int){
prog.hidden=false
prog.doubleValue=0
prog.maxValue=7*40
让优先级=调度队列优先级高
调度异步(调度获取全局队列(优先级为0)){
self.theFunc(n,var1:0.06,var2:0.06,var3:7)
self.theFunc(n,var1:0.1*log(Double(n))/Double(n),var2:0.3*log(Double(n))/Double(n),var3:7)
dispatch\u async(dispatch\u get\u main\u queue()){
self.prog.hidden=true
self.appOut(“完成!”)
}
}
}
//这并不重要
//func函数(n:Int,var1:Double,var2:Double,var3:Int){
//var m:茴香
//var gra:某个类
//var p=var1
//对于0中的uu…(var3-1){
//var str=“blah\(p)\n”
//对于1…20中的uu{
//gra=SomeClass(尺寸:n,pro:p)!
//m=自身剂量(gra)
//开关m{
//案例。首先(让dat):
//str=str+“Blah:\n\(self.arrayF(dat,transform:{“Blah\($0)Blah\($1)=Blah”}))“+”\n\n”+str
//第二种情况(让odat):
//str=str+“Blah\(odat.count)Blah\(self.arrayF(odat,transform:{“bl\($1)”)”+“\n\n”+str
//              }
//dispatch\u async(dispatch\u get\u main\u queue()){
//自编程增量(1)
//              }
//          }
//dispatch\u async(dispatch\u get\u main\u queue()){
////更新一些用户界面
//self.display.string=str+“\n”+(self.display.string???”)
//          }
//p+=var2
//      }
//  }
//这很有效
func函数(n:Int,var1:Double,var2:Double,var3:Int){
var m:茴香
var gra:某个类
var p=var1
对于0中的uu…(var3-1){
var str=“blah\(p)\n”
对于1…20中的uu{
gra=SomeClass(尺寸:n,pro:p)!
m=自身剂量(gra)
开关m{
案例。首先(让dat):
str=“Blah:\n\(self.arrayF(dat,transform:{“Blah\($0)Blah\($1)=Blah”}”)”+“\n\n”+str
第二种情况(让odat):
str=“Blah\(odat.count)Blah\(self.arrayF(odat,transform:{“bl\($1)”)”+“\n\n”+str
}
dispatch\u async(dispatch\u get\u main\u queue()){
自编程增量(1)
}
}
dispatch\u async(dispatch\u get\u main\u queue()){
//更新一些用户界面
self.display.string=str+“\n”+(self.display.string???”)
}
p+=var2
}
}
func doSomething(G:SomeClass)->AnEnum{
美国LEEP(30000)
如果drand48()字符串)->字符串{
设arr=Array(0…(Array.count-1))
返回“[\(arr.map{transform(索引:$0,值:数组[$0])}.joinWithSeparator(“,”)”)
}
}

因为你不是在问一个问题

你能相信吗

我会告诉你,我当然可以,但说真的,在很多情况下,预结束某些内容可能比追加慢/快。以链表为例。如果不引用列表的最后一个元素,则预结束是O(1),追加是O(N)

我总结了这个问题的要点,在5-6次运行时,它似乎并没有显著的差异,但是prepend在我的机器上仍然慢10%

有趣的是,关于您的案例,您基本上有4种在Swift中连接字符串的方法:

  • 前置到累加器
    str=newstr+str
  • 附加到累加器
    str=str+newstr
  • 追加变异
    str.append(newstr)
  • 使用好的旧数组作为字符串缓冲区,一次连接所有数组
    a=[];a.append(x);str=a.joined(分隔符:“”)
在我的机器上,它们似乎几乎在同一时间偏离,典型的计时方式如下:

prepend
real    0m0.082s
user    0m0.060s
sys 0m0.018s

append
real    0m0.070s
user    0m0.049s
sys 0m0.018s

append mutate
real    0m0.075s
user    0m0.054s
sys 0m0.019s

join
real    0m0.086s
user    0m0.064s
sys 0m0.020s
他跑得最快

您可以在我的要点中看到所有四种情况的代码

如果您在Github上查看Swift sources,您将看到:

@effects(readonly)
@_semantics("string.concat")
public static func + (lhs: String, rhs: String) -> String {
 if lhs.isEmpty {
  return rhs
 }
 var lhs = lhs
 lhs._core.append(rhs._core)
 return lhs
}

因此,随着累加器字符串的增长,复制它的成本可能会更高。

Vittore的答案是正确的。查看Swift的字符串()源代码,我们可以看到:

虽然Swift中的字符串具有值语义,但字符串在写入时使用副本 将数据存储在缓冲区中的策略。此缓冲区可以