2016-11-24 45 views
1
import XCTest 

class testTests: XCTestCase { 
    static func makearray() -> [Int] { 
     var array: [Int] = [] 
     for x in 0..<1000000 { 
      array.append(x) 
     } 
     return array 
    } 

    let array = testTests.makearray() 

    func testPerformanceExample() { 
     self.measure { 
      var result: [String] = [] 
      for x in self.array { 
      let tmp = "string\(x)" 
      if tmp.hasSuffix("1234") { 
       result.append(tmp) 
      } 
     } 
     print(result.count) 
    } 
} 

func testPerformanceExample2() { 
    self.measure { 
     let result = self.array.map { "string\($0)" } 
           .filter { $0.hasSuffix("1234") } 
     print(result.count) 
    } 
} 

func testPerformanceExample3() { 
    self.measure { 
     let result = self.array.flatMap { int -> String? in 
      let tmp = "string\(int)" 
      return tmp.hasSuffix("1234") ? tmp : nil 
     } 
     print(result.count) 
    } 
} 
} 

在这段代码中,我试图看看高阶函数如何处理大数组。在Swift中改进高阶函数与循环的性能(3.0)

3次测试产生相同的结果,对于循环,1.38s映射/滤波器,1.21s平面映射,时间约为0.75s。

假设HOFs或多或少是函数包装循环,这在地图/过滤器的情况下很有意义,它通过第一个数组循环遍历map,然后遍历结果过滤。

在flatmap的情况下,它是先做图,然后再做一个更简单的过滤操作?

我的理解是什么在引擎盖下(大致)正确的?

如果是这样,说编译器无法对此做很多优化是否公平?

最后,有没有更好的方法来做到这一点? HOF版本对我来说绝对是更容易理解的,但对于性能关键领域,看起来for循环是要走的路?

+2

你真的遇到这样的情况该事项,或者这只是理论上的? – matt

+0

另外,如果性能非常关键,那么你肯定会直接写入内存。所以我有点麻烦,认为这不过是浪费时间。 – matt

+0

你真的告诉编译器优化吗?如果没有,这一切都是毫无意义的,不是吗? – matt

回答

3

平面地图方法很可能与循环方法几乎等价。算法上,它是等价的。我想补充一点,即使在这种情况下,map/filter方法也应该“近”地快,因为字符串上的操作占用了大量的运行时间。

为了获得良好的性能,人们希望避免使用临时字符串。我们可以达到理想的效果如下...

func fastloopflatmap (_ test_array: [Int]) -> [String] { 
    var result: [String] = [] 
    for x in array { 
     if x % 10000 == 1234 { 
      result.append("string\(x)") 
     } 
    } 
    return result; 
} 

这里是我的时刻:

loop  : 632 ns/element 
filter/map : 650 ns/element 
flatmap  : 632 ns/element 
fast loop : 1.2 ns/element 

因此,你可以看到,缓慢的运行时间的大部分(99%)函数是由于临时字符串的操作。

的源代码:https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/extra/swift/flatmap