你能相信吗?我有一个这样的循环(原谅任何错误,我不得不大量地编辑许多信息和变量名称,相信我,它是有效的)。
...Old示例编辑完毕,请参阅下面的代码..。
如果我把那些中间的str = "Blah \(odat.count)" + str类型的线改为str = str + "Blah \(odat.count)",UI就会停止运行,我得到了彩色的轮子。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(", "))]"
}
}发布于 2016-09-22 21:30:38
因为你不是在问其他的问题
你能相信吗?
我会告诉你,我当然可以,但说真的,有很多情况下,预先准备的东西可能比附加更慢/更快。例如,链接列表。Prepend是O(1),如果不保存对列表最后一个元素的引用,则追加为O(N)。
我把要点放在一起,就是这个问题的一倍,在5-6的运行中,它似乎没有明显的差别,但是在我的机器上预置速度仍然慢了10%。
有趣的是,对于您的情况,您基本上有4种在Swift中连接字符串的方法:
str = newstr + strstr = str + newstrstr.append(newstr)a = []; a.append(x); str = a.joined(separator: " ")。在我的机器上,它们似乎几乎都在同一时间偏离,典型的计时方式是这样的:
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是最快的。
您可以在gist https://gist.github.com/ojosdegris/df72a94327d12a67fe65e5989f9dcc53中看到所有四种情况的代码
如果您查看了Github上的Swift源代码,您将看到以下内容:
@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
}因此,随着累加器字符串的增长,复制它的成本可能会更高。
发布于 2016-09-28 13:37:54
维特雷的回答是正确的。查看Swift的字符串源代码(stdlib/public/core/String.ES-10),我们可以看到:
虽然Swift中的字符串具有值语义,但是字符串使用写复制策略将数据存储在缓冲区中。然后,这个缓冲区可以由一个字符串的不同副本共享。当多个字符串实例使用相同的缓冲区时,字符串的数据只有在变异时才被延迟地复制。因此,在任意序列的变异操作中,第一步可能会花费O(n)时间和空间。 当字符串的连续存储被填满时,必须分配一个新的缓冲区,并且必须将数据移动到新的存储。字符串缓冲区使用一种指数增长策略,当对多个附加操作进行平均处理时,在字符串中追加一个恒定的时间操作。
维基百科的抄写
如果资源被复制但没有修改,则不需要创建新资源;该资源可以在副本和原始资源之间共享。
考虑到这一点,在执行str = str + "abc"时,编译器将执行str的浅拷贝,并将"abc"附加到其连续内存中。另一方面,str = "abc" + str使用自己独特的数据副本创建了一个独立的实例,因为它不再使用连续内存。
https://stackoverflow.com/questions/39376005
复制相似问题