swift2 Swift 2中连接字符串的最快方法

fcy6dtqo  于 2022-11-06  发布在  Swift
关注(0)|答案(5)|浏览(198)

在Swift 2中,连接多个字符串的最快、最有效的方法是什么?

// Solution 1...
let newString:String = string1 + " " + string2
// ... Or Solution 2?
let newString:String = "\(string1) \(string2)"

或者,唯一的区别是它在程序员看来的样子?

lawou6xi

lawou6xi1#

我在模拟器和iPhone6S Plus上运行了下面的代码。两种情况下的结果都显示,对于我使用的字符串,string1 + " " + string2加法更快。我没有尝试使用不同类型的字符串、优化等,但您可以运行代码并检查特定的字符串等。尝试在IBM Swift沙箱中在线运行此代码。计时器结构来自以下内容:在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 RunTimer: CustomStringConvertible {
        var begin: CFAbsoluteTime
        var end:CFAbsoluteTime

        init() {
            begin = CFAbsoluteTimeGetCurrent()
            end = 0
        }

        mutating func start() {
            begin = CFAbsoluteTimeGetCurrent()
            end = 0
        }

        @discardableResult
        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 = RunTimer()

        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视网膜):

+   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,看看分配和释放等的时间是如何分配的,与机器码有关,也显示在那里。

ojsjcaue

ojsjcaue2#

这个问题激起了我的好奇心,所以我把这个放进了一个新的项目。这些都是快速而肮脏的基准,应该与通常的盐粒采取,但结果是耐人寻味的。

var string1 = "This"
var string2 = "that"
var newString: String

let startTime = NSDate()
for _ in 1...100000000 {
  newString = string1 + " " + string2
}
print("Diff: \(startTime.timeIntervalSinceNow * -1)")

在我的MacBook Pro(2014年中的i7,2.5GHz)上运行的模拟器上运行6次,输出到调试控制台的平均时间为1.36秒。作为调试代码部署到我的iPhone 6S上,6次运行的所有输出的平均时间为1.33秒。
使用相同的代码,但将字符串连接到的行更改为...

newString = "\(string1) \(string2)"

......给了我一个不一样的结果,模拟器上运行6次,调试台上报告的平均时间是50.86秒,iPhone 6S上运行6次,平均时间是88.82秒,这几乎是两个数量级的差距。
这些结果表明,如果必须连接大量字符串,则应使用+运算符,而不是字符串插值。

0pizxfdo

0pizxfdo3#

最快的方法可能取决于实现。您可以对编译器、编译器优化设置、库、框架、操作系统和处理器/CPU的特定组合进行基准测试。但在不同的组合下,性能可能会有很大差异。
对于string 1和string 2是否可变,答案也可能不同,但这也取决于编译器优化级别。

33qvvth1

33qvvth14#

雨燕3

在Swift 3中连接字符串的另一种方法是使用joined

let stringArray = ["string1", "string2"]
let newString = stringArray.joined(separator: " ")

当然,这要求字符串在一个数组中。我没有做过任何时间配置文件,所以不能将其与其他建议的解决方案进行比较。

zi8p0yeb

zi8p0yeb5#

TL;DR:只有在处理大字符串(数百万字节/字符)时,差异才会明显。

所有测试均在iMac 21.5 Late 2012, 2.7GHz Intel Core i5上编译和执行。
我做了一个小的基准测试。下面是代码。

插值.swiftswiftc ./interpolation.swift -o ./interpolation编译

import Swift

_ = "\(Process.arguments[1]) \(Process.arguments[2])"

-emit-assembly标志的swiftc的输出:

.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    $128, %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    $5, %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    $1, %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    $1, %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    $1, %r8d
    movl    %r8d, %esi
    movl    $1, %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    $2, %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    $1, %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    $128, %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.swift+运算符)用swiftc ./addstr.swift -o ./addstr编译

import Swift

_ = Process.arguments[1] + " " + Process.arguments[2]

-emit-assembly标志的swiftc的输出:

.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    $176, %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    $1, %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    $1, %r8d
    movl    %r8d, %esi
    movl    $1, %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    $2, %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    $176, %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.swift的程序集包含的命令比interpolation.swift少。
以下是使用/usr/bin/time进行计时的基准测试结果(bash-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.001s)。

相关问题