मैं स्विफ्ट में कुछ प्रदर्शन-महत्वपूर्ण कोड लिख रहा हूं। सभी ऑप्टिमाइज़ेशन को लागू करने के बाद, मैं इंस्ट्रूमेंट्स में एप्लिकेशन के बारे में सोच सकता हूं और प्रोफाइलिंग कर सकता हूं, मुझे एहसास हुआ कि सीपीयू चक्रों का विशाल बहुमत फ्लोट के सरणी पर map()
और reduce()
संचालन करने में व्यतीत होता है। तो, यह देखने के लिए कि क्या होगा, मैंने map
और reduce
के सभी उदाहरणों को अच्छी पुरानी for
लूप के साथ बदल दिया। और मेरे आश्चर्य के लिए ... for
लूप बहुत तेज थे!स्विफ्ट प्रदर्शन: लूप के लिए मानचित्र() और कम() बनाम
इससे थोड़ा परेशान, मैंने कुछ मोटे बेंचमार्क करने का फैसला किया।
// Populate array with 1,000,000,000 random numbers
var array = [Float](count: 1_000_000_000, repeatedValue: 0)
for i in 0..<array.count {
array[i] = Float(random())
}
let start = NSDate()
// Construct a new array, with each element from the original multiplied by 5
let output = array.map({ (element) -> Float in
return element * 5
})
// Log the elapsed time
let elapsed = NSDate().timeIntervalSinceDate(start)
print(elapsed)
और बराबर for
पाश कार्यान्वयन: 20.1 सेकंड:
var output = [Float]()
for element in array {
output.append(element * 5)
}
map
के लिए औसत निष्पादन समय एक परीक्षण में, मैं map
वापसी तो जैसे कुछ साधारण अंकगणित प्रदर्शन के बाद मंगाई की एक सरणी था। for
लूप के लिए औसत निष्पादन समय: 11.2 सेकंड। परिणाम फ़्लोट्स के बजाय इंटेजर्स का उपयोग कर समान थे।
मैंने स्विफ्ट के reduce
के प्रदर्शन का परीक्षण करने के लिए एक समान बेंचमार्क बनाया। इस बार, reduce
और for
लूप्स ने एक बड़े सरणी के तत्वों को संक्षेप में लगभग समान प्रदर्शन प्राप्त किया। लेकिन जब मैं पाश परीक्षण 100,000 बार इस तरह:
// Populate array with 1,000,000 random numbers
var array = [Float](count: 1_000_000, repeatedValue: 0)
for i in 0..<array.count {
array[i] = Float(random())
}
let start = NSDate()
// Perform operation 100,000 times
for _ in 0..<100_000 {
let sum = array.reduce(0, combine: {$0 + $1})
}
// Log the elapsed time
let elapsed = NSDate().timeIntervalSinceDate(start)
print(elapsed)
बनाम:
for _ in 0..<100_000 {
var sum: Float = 0
for element in array {
sum += element
}
}
जबकि for
पाश (जाहिरा तौर पर) 0.000003 सेकंड लेता है reduce
विधि 29 सेकंड लेता है।
स्वाभाविक रूप से मैं एक कंपाइलर अनुकूलन के परिणामस्वरूप उस अंतिम परीक्षण को नजरअंदाज करने के लिए तैयार हूं, लेकिन मुझे लगता है कि यह कुछ अंतर्दृष्टि दे सकता है कि कंपाइलर स्विफ्ट के अंतर्निर्मित सरणी विधियों बनाम लूप के लिए अलग-अलग कैसे अनुकूलित करता है। ध्यान दें कि सभी परीक्षणों को 2.5 गीगाहर्ट्ज i7 मैकबुक प्रो पर ऑप्टिमाइज़ेशन के साथ किया गया था। परिणाम सरणी आकार और पुनरावृत्तियों की संख्या के आधार पर भिन्न होते हैं, लेकिन for
लूप हमेशा कम से कम 1.5x, अन्यथा 10x तक अन्य तरीकों से बेहतर प्रदर्शन करते हैं।
मैं यहां स्विफ्ट के प्रदर्शन के बारे में थोड़ा परेशान हूं। क्या इस तरह के परिचालन करने के लिए अंतर्निहित ऐरे विधियों को निष्क्रिय दृष्टिकोण से तेज नहीं होना चाहिए? हो सकता है कि कोई व्यक्ति निम्न स्तर के ज्ञान के साथ स्थिति पर कुछ प्रकाश डाल सके।
शायद, संकलक को पता चलता है कि आपके अंतिम उदाहरण में, संक्षेप का परिणाम बिल्कुल उपयोग नहीं किया जाता है और पूरे पाश को हटा देता है। लूप को एक फर्क पड़ने के बाद राशि प्रिंट करना। –
अच्छा विचार - जो निश्चित रूप से इसे धीमा कर देता है। हालांकि ईमानदारी से, मेरे अनुभव में प्रिंट प्रिंट() कि कई बार अविश्वसनीय रूप से धीमा है, इसलिए यह कहना मुश्किल है कि इससे क्या फर्क पड़ता है। हालांकि यह दो विधियों के बीच अनुकूलन अंतर का एक अच्छा उदाहरण है - ऐसा लगता है कि इसे कम() लूप के बारे में भी एक ही निष्कर्ष निकालना चाहिए। – hundley
शायद यह आलेख फॉर-लूप के बीच प्रदर्शन अंतरों पर कुछ अंतर्दृष्टि दे सकता है और कम हो जाता है: http://airspeedvelocity.net/2015/08/03/arrays-linked-lists-and-performance/ – JDS