2016-11-24 36 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