【问题标题】:Performance degradation on reading .txt files in Swift在 Swift 中读取 .txt 文件时的性能下降
【发布时间】:2016-04-11 19:29:35
【问题描述】:

我有一个用数字填充的文本文件,并按如下方式读取文件内容

func arrayFromContentsOfFileWithName(fileName: String) -> [String]? {
guard let path = NSBundle.mainBundle().pathForResource(fileName, ofType: "txt") else {
    return nil
}

do {
    let content = try String(contentsOfFile:path, encoding: NSUTF8StringEncoding)
    return content.componentsSeparatedByString("\n")
} catch _ as NSError {
    return nil
}}

但是,当我检查性能时, content.componentsSeparatedByString("\n") 似乎存在瓶颈,如下所示:

有人可以提出解决此问题的方法吗?或者可以将整个文本文件一次性读取为双精度值,如下所示:

let B1: [Float] = [0.0584000014, 0.0905999988, 0.0916000009, 0.0640999973, 0.0824000016, 0.0960000008, 0.0776999965, 0.0936999992, 0.0908999965, 0.0568999983, 0.0654999986, 0.0535999984, 0.0901999995, 0.0724999979, 0.104900002, 0.0798000023, 0.0962999985, 0.0914999992, 0.0680999979, 0.110100001, 0.0648000017, 0.103299998, 0.077200003, 0.0821999982, 0.0778999999, 0.074000001, 0.0710999966, 0.108499996, 0.060899999, 0.0697000027, 0.0841000006, 0.061900001]

【问题讨论】:

  • 为什么不使用 plist 而不是常规的文本文件?
  • @Leo Dabus,如何使用 plist 读取值?有这方面的教程吗?

标签: arrays swift core-data optimization


【解决方案1】:

那是因为创建新的String 很慢。我没有查看 Swift 的源代码来了解原因,但这似乎是 Swift 从 ObjC 继承下来的一个特征。最重要的是,您必须将String 转换为Float,这也不是一个快速的操作。

改用NSScanner

func timeBlock(label: String, block: () -> Void) {
    let start = NSDate().timeIntervalSince1970
    block()
    let end = NSDate().timeIntervalSince1970

    print("\(label): \(end - start) seconds")
}

func f1 (fileContent: String) -> [Float] {
    return fileContent.componentsSeparatedByString("\n")
                .flatMap { Float($0) }
}

func f2 (fileContent: String) -> [Float] {
    let scanner = NSScanner(string: fileContent)
    var result = [Float]()

    while !scanner.atEnd {
        var x: Float = 0
        scanner.scanFloat(&x)
        result.append(x)
    }

    return result
}


do {
    let content = try String(contentsOfFile: path, encoding: NSUTF8StringEncoding)
    timeBlock("f1") { f1(content) }
    timeBlock("f2") { f2(content) }
} catch let error as NSError {
    print(error.localizedDescription)
}

我创建了一个随机文件,其中包含 1M 行数字作为输入。 NSScanner 大约快 5.3 倍:

f1: 4.2731032371521 seconds
f2: 0.82185697555542 seconds

【讨论】:

  • 不错的答案。不过,我对 NSScanner 的性能感到有些惊讶。我猜我期待它会更快。
  • 这真是太好了。至少比创建新的 String 方法要好。竖起大拇指!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多