Самый быстрый способ объединить строки в Swift 2
какой самый быстрый и эффективный способ объединить несколько строк в Swift 2?
// Solution 1...
let newString:String = string1 + " " + string2
// ... Or Solution 2?
let newString:String = "(string1) (string2)"
или это только дифференциация, как она выглядит для программиста?
5 ответов
Я запустил следующий код в симуляторе и на iPhone6S Plus. Результаты в обоих случаях показали string1 + " " + string2
добавление быстрее для строк, которые я использовал. Я не пытался использовать различные типы строк, оптимизации и т. д. но вы можете запустить код и проверить свои конкретные строки и т. д. Попробуйте запустить этот код онлайн в IBM Swift Sandbox.
Таймер struct-это здесь: измерение прошедшего времени в swift
для запуска кода создайте один просмотрите приложение в Xcode и добавьте следующий код в ViewController:
import UIKit
import CoreFoundation
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let a = "abscdefghi jkl¢€@sads dljlæejktæljæ leijroptjiæa Dog! iojeg r æioej rgæoija"
let b = a
timeStringAdding(a, string2: b, times: 1_000_000, repetitions: 5)
}
struct RunningTimer: CustomStringConvertible {
var begin:CFAbsoluteTime
var end:CFAbsoluteTime
init() {
begin = CFAbsoluteTimeGetCurrent()
end = 0
}
mutating func start() {
begin = CFAbsoluteTimeGetCurrent()
end = 0
}
mutating func stop() -> Double {
if (end == 0) { end = CFAbsoluteTimeGetCurrent() }
return Double(end - begin)
}
var duration:CFAbsoluteTime {
get {
if (end == 0) { return CFAbsoluteTimeGetCurrent() - begin }
else { return end - begin }
}
}
var description:String {
let time = duration
if (time > 100) {return " \(time/60) min"}
else if (time < 1e-6) {return " \(time*1e9) ns"}
else if (time < 1e-3) {return " \(time*1e6) µs"}
else if (time < 1) {return " \(time*1000) ms"}
else {return " \(time) s"}
}
}
func timeStringAdding(string1:String, string2:String, times:Int, repetitions:Int) {
var newString = ""
var i = 0
var j = 0
var timer = RunningTimer.init()
while j < repetitions {
i = 0
timer.start()
while i < times {
newString = string1 + " " + string2
i += 1
}
print("+ add \(timer)")
i = 0
timer.start()
while i < times {
newString = "\(string1) \(string2)"
i += 1
}
print("\( add \(timer)")
j += 1
}
}
}
на iPhone 6s Plus он дал:
+ add 727.977991104126 ms
\( add 1.1197350025177 s
+ add 693.499982357025 ms
\( add 1.11982899904251 s
+ add 690.113961696625 ms
\( add 1.12086200714111 s
+ add 707.363963127136 ms
\( add 1.13451600074768 s
+ add 734.095990657806 ms
\( add 1.19673496484756 s
и на симуляторе (iMac Retina):
+ add 406.143009662628 ms
\( add 594.823002815247 ms
+ add 366.503953933716 ms
\( add 595.698952674866 ms
+ add 370.530009269714 ms
\( add 596.457958221436 ms
+ add 369.667053222656 ms
\( add 594.724953174591 ms
+ add 369.095981121063 ms
\( add 595.37798166275 ms
большую часть времени это выделение и освобождение памяти для строковых структур, а для тех, кто действительно любопытен, запустите код в Instruments panel
С Time Profiler
использование и посмотреть, как время выделяется для alloc и free etc, по отношению к машинному коду, который показан там также.
этот вопрос возбудил мое любопытство, поэтому я поместил это в новый проект. Это быстрые и грязные тесты и их следует принимать с обычными зернами соли, но результаты были интригующими.
var string1 = "This"
var string2 = "that"
var newString: String
let startTime = NSDate()
for _ in 1...100000000 {
newString = string1 + " " + string2
}
print("Diff: \(startTime.timeIntervalSinceNow * -1)")
В 6 запусках на симуляторе, работающем на моем MacBook Pro (mid-2014 i7, 2.5 GHz), выход на консоль отладки составил в среднем 1,36 секунды. Развернутый как отладочный код на моем iPhone 6S, средний из всех выходов за 6 запусков составил 1,33 секунды.
используя тот же код, но изменение строки, в которой строки объединены с этим...
newString = "\(string1) \(string2)"
...дал мне совсем другие результаты. В 6 запусках на симуляторе среднее время, сообщенное на консоли отладки, составило 50,86 секунды. В 6 запусках на iPhone 6S среднее время выполнения составляло 88,82 секунды. Это почти 2 порядка разницы.
эти результаты предполагают, что если вам нужно объединить большое количество строк, вы должны использовать +
оператор, а не строку интерполяция.
самый быстрый способ, вероятно, зависит от реализации. Вы можете проверить свою конкретную комбинацию компилятора, настроек оптимизации компилятора, библиотеки, фреймворка, ОС и процессора/процессора. Но, вероятно, производительность может быть очень разной при другой комбинации.
ответ может также отличаться от того, являются ли string1 и string2 изменяемыми или нет, но также в зависимости от уровня оптимизации компилятора.
Swift 3
другой способ объединить строки в Swift 3-Использовать joined
:
let stringArray = ["string1", "string2"]
let newString = stringArray.joined(separator: " ")
конечно, для этого требуется, чтобы строки находились в массиве. Я не делал никакого профиля времени, поэтому не могу сравнить его с другими предлагаемыми решениями.
TL; DR: разница заметна только при работе с большими строками (миллионы байтов/символов).
все тесты были скомпилированы и выполнены на iMac 21.5 конец 2012, 2.7 ГГц Intel Core i5.
Я сделал небольшой тест. Вот код.
интерполяция.Свифт!--15--> составлен с swiftc ./interpolation.swift -o ./interpolation
import Swift
_ = "\(Process.arguments[1]) \(Process.arguments[2])"
выход swiftc
С -emit-assembly
флаг:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 9
.globl _main
.align 4, 0x90
_main:
.cfi_startproc
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq 8, %rsp
movq _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token5@GOTPCREL(%rip), %rax
movq __TZvOs7Process5_argcVs5Int32@GOTPCREL(%rip), %rcx
movl %edi, (%rcx)
cmpq $-1, (%rax)
movq %rsi, -56(%rbp)
je LBB0_2
movq _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token5@GOTPCREL(%rip), %rdi
movq _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_func5@GOTPCREL(%rip), %rax
movq %rax, %rsi
callq _swift_once
LBB0_2:
movl , %eax
movl %eax, %edi
movq __TZvOs7Process11_unsafeArgvGSpGSpVs4Int8__@GOTPCREL(%rip), %rcx
movq -56(%rbp), %rdx
movq %rdx, (%rcx)
callq __TTSg5SS___TFs27_allocateUninitializedArrayurFBwTGSax_Bp_
leaq L___unnamed_1(%rip), %rdi
xorl %esi, %esi
movl , %r8d
movq %rdx, -64(%rbp)
movl %r8d, %edx
movq %rax, -72(%rbp)
callq __TFSSCfT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS
movq %rax, %rdi
movq %rdx, %rsi
movq %rcx, %rdx
callq __TFSSCfT26stringInterpolationSegmentSS_SS
movq -64(%rbp), %rsi
movq %rax, (%rsi)
movq %rdx, 8(%rsi)
movq %rcx, 16(%rsi)
callq __TFOs7Processau9argumentsGSaSS_
movq (%rax), %rax
movq %rax, %rdi
movq %rax, -80(%rbp)
callq _swift_bridgeObjectRetain
leaq -24(%rbp), %rdi
movl , %r8d
movl %r8d, %esi
movq -80(%rbp), %rdx
movq %rax, -88(%rbp)
callq __TTSg5SS___TFSag9subscriptFSix
movq -80(%rbp), %rdi
callq _swift_bridgeObjectRelease
movq -24(%rbp), %rdi
movq -16(%rbp), %rsi
movq -8(%rbp), %rdx
callq __TFSSCfT26stringInterpolationSegmentSS_SS
leaq L___unnamed_2(%rip), %rdi
movl , %r8d
movl %r8d, %esi
movl , %r8d
movq -64(%rbp), %r9
movq %rax, 24(%r9)
movq %rdx, 32(%r9)
movq %rcx, 40(%r9)
movl %r8d, %edx
callq __TFSSCfT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS
movq %rax, %rdi
movq %rdx, %rsi
movq %rcx, %rdx
callq __TFSSCfT26stringInterpolationSegmentSS_SS
movq -64(%rbp), %rsi
movq %rax, 48(%rsi)
movq %rdx, 56(%rsi)
movq %rcx, 64(%rsi)
callq __TFOs7Processau9argumentsGSaSS_
movq (%rax), %rax
movq %rax, %rdi
movq %rax, -96(%rbp)
callq _swift_bridgeObjectRetain
leaq -48(%rbp), %rdi
movl , %r8d
movl %r8d, %esi
movq -96(%rbp), %rdx
movq %rax, -104(%rbp)
callq __TTSg5SS___TFSag9subscriptFSix
movq -96(%rbp), %rdi
callq _swift_bridgeObjectRelease
movq -48(%rbp), %rdi
movq -40(%rbp), %rsi
movq -32(%rbp), %rdx
callq __TFSSCfT26stringInterpolationSegmentSS_SS
leaq L___unnamed_1(%rip), %rdi
xorl %r8d, %r8d
movl %r8d, %esi
movl , %r8d
movq -64(%rbp), %r9
movq %rax, 72(%r9)
movq %rdx, 80(%r9)
movq %rcx, 88(%r9)
movl %r8d, %edx
callq __TFSSCfT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS
movq %rax, %rdi
movq %rdx, %rsi
movq %rcx, %rdx
callq __TFSSCfT26stringInterpolationSegmentSS_SS
movq -64(%rbp), %rsi
movq %rax, 96(%rsi)
movq %rdx, 104(%rsi)
movq %rcx, 112(%rsi)
movq -72(%rbp), %rdi
callq __TFSSCft19stringInterpolationGSaSS__SS
movq %rcx, %rdi
movq %rax, -112(%rbp)
movq %rdx, -120(%rbp)
callq _swift_unknownRelease
xorl %eax, %eax
addq 8, %rsp
popq %rbp
retq
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L___unnamed_1:
.space 1
L___unnamed_2:
.asciz " "
.linker_option "-lswiftCore"
.linker_option "-lobjc"
.section __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
.long 0
.long 768
.subsections_via_symbols
addstr.Свифт!--15--> (+
оператор) составлена с swiftc ./addstr.swift -o ./addstr
import Swift
_ = Process.arguments[1] + " " + Process.arguments[2]
выход swiftc
С -emit-assembly
флаг:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 9
.globl _main
.align 4, 0x90
_main:
.cfi_startproc
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq 6, %rsp
movq _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token5@GOTPCREL(%rip), %rax
movq __TZvOs7Process5_argcVs5Int32@GOTPCREL(%rip), %rcx
movl %edi, (%rcx)
cmpq $-1, (%rax)
movq %rsi, -56(%rbp)
je LBB0_2
movq _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_token5@GOTPCREL(%rip), %rdi
movq _globalinit_33_1BDF70FFC18749BAB495A73B459ED2F0_func5@GOTPCREL(%rip), %rax
movq %rax, %rsi
callq _swift_once
LBB0_2:
movq __TZvOs7Process11_unsafeArgvGSpGSpVs4Int8__@GOTPCREL(%rip), %rax
movq -56(%rbp), %rcx
movq %rcx, (%rax)
callq __TFOs7Processau9argumentsGSaSS_
movq (%rax), %rax
movq %rax, %rdi
movq %rax, -64(%rbp)
callq _swift_bridgeObjectRetain
leaq -24(%rbp), %rdi
movl , %edx
movl %edx, %esi
movq -64(%rbp), %rdx
movq %rax, -72(%rbp)
callq __TTSg5SS___TFSag9subscriptFSix
movq -64(%rbp), %rdi
callq _swift_bridgeObjectRelease
leaq L___unnamed_1(%rip), %rdi
movl , %r8d
movl %r8d, %esi
movl , %edx
movq -24(%rbp), %rax
movq -16(%rbp), %rcx
movq -8(%rbp), %r9
movq %r9, -80(%rbp)
movq %rcx, -88(%rbp)
movq %rax, -96(%rbp)
callq __TFSSCfT21_builtinStringLiteralBp8byteSizeBw7isASCIIBi1__SS
movq -96(%rbp), %rdi
movq -88(%rbp), %rsi
movq -80(%rbp), %r9
movq %rdx, -104(%rbp)
movq %r9, %rdx
movq %rcx, -112(%rbp)
movq %rax, %rcx
movq -104(%rbp), %r8
movq -112(%rbp), %r9
callq __TZFsoi1pFTSSSS_SS
movq %rax, -120(%rbp)
movq %rdx, -128(%rbp)
movq %rcx, -136(%rbp)
callq __TFOs7Processau9argumentsGSaSS_
movq (%rax), %rax
movq %rax, %rdi
movq %rax, -144(%rbp)
callq _swift_bridgeObjectRetain
leaq -48(%rbp), %rdi
movl , %r10d
movl %r10d, %esi
movq -144(%rbp), %rdx
movq %rax, -152(%rbp)
callq __TTSg5SS___TFSag9subscriptFSix
movq -144(%rbp), %rdi
callq _swift_bridgeObjectRelease
movq -48(%rbp), %rcx
movq -40(%rbp), %r8
movq -32(%rbp), %r9
movq -120(%rbp), %rdi
movq -128(%rbp), %rsi
movq -136(%rbp), %rdx
callq __TZFsoi1pFTSSSS_SS
movq %rcx, %rdi
movq %rax, -160(%rbp)
movq %rdx, -168(%rbp)
callq _swift_unknownRelease
xorl %eax, %eax
addq 6, %rsp
popq %rbp
retq
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L___unnamed_1:
.asciz " "
.linker_option "-lswiftCore"
.linker_option "-lobjc"
.section __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
.long 0
.long 768
.subsections_via_symbols
как видите, собрание addstr.Свифт!--15--> содержит меньше команд, чем интерполяция.Свифт!--15-->.
вот результаты тестирования с помощью /usr/bin/time
по времени (Баш-3.2).
$ ARG1=$(printf '%.0s' {1..30000}) # 30000 '' characters
$ ARG2=$(printf '%.0s' {1..30000}) # 30000 '' characters
$ time ./interpolation $ARG1 $ARG2
>
> real 0m0.026s
> user 0m0.018s
> sys 0m0.006s
$ time ./addstr $ARG1 $ARG2
>
> real 0m0.026s
> user 0m0.018s
> sys 0m0.006s
я провел этот тест много раз, но результаты всегда были одинаковыми ( ±0.001 s).