2012-05-06 14 views
8

मैं एफ # सीख रहा हूं और एक चीज जो मुझे इस भाषा के बारे में बताती है वह प्रदर्शन है। मैंने एक छोटा बेंचमार्क लिखा है जहां मैं एक ही भाषा में लिखे गए अनिवार्य-शैली कोड के लिए idiomatic F # की तुलना करता हूं - और मेरे आश्चर्य के लिए, कार्यात्मक संस्करण काफी तेज़ी से आता है। File.ReadAllLines लूप के लिए नियमित से Seq.map तेज?

  • प्रत्येक पंक्ति
  • वापस एक ही फाइल File.WriteAllLines का उपयोग करने के परिणाम लेखन के भीतर पात्रों के आदेश पीछे का उपयोग कर एक पाठ फ़ाइल में

    1. पढ़ना:

      बेंचमार्क के होते हैं ।

    कोड यह रहा:

    open System 
    open System.IO 
    open System.Diagnostics 
    
    let reverseString(str:string) = 
        new string(Array.rev(str.ToCharArray())) 
    
    let CSharpStyle() = 
        let lines = File.ReadAllLines("text.txt") 
        for i in 0 .. lines.Length - 1 do 
         lines.[i] <- reverseString(lines.[i]) 
    
        File.WriteAllLines("text.txt", lines) 
    
    let FSharpStyle() = 
        File.ReadAllLines("text.txt") 
        |> Seq.map reverseString 
        |> (fun lines -> File.WriteAllLines("text.txt", lines)) 
    
    let benchmark func message = 
        // initial call for warm-up 
        func() 
    
        let sw = Stopwatch.StartNew() 
        for i in 0 .. 19 do 
         func() 
    
        printfn message sw.ElapsedMilliseconds 
    
    
    [<EntryPoint>] 
    let main args = 
        benchmark CSharpStyle "C# time: %d ms" 
        benchmark FSharpStyle "F# time: %d ms" 
        0 
    

    जो भी फ़ाइल का आकार, "एफ # शैली" संस्करण "सी # शैली" संस्करण के समय 75% के आसपास में पूरा करता है। मेरा सवाल है, वह क्यों है? मुझे अनिवार्य संस्करण में कोई स्पष्ट अक्षमता दिखाई नहीं दे रही है।

  • +1

    कुडोस @ डीआर_एसिक एक अच्छी तरह से तैयार प्रश्न के लिए। –

    उत्तर

    10

    Seq.mapArray.map से अलग है। चूंकि अनुक्रम (IEnumerable<T>) का मूल्यांकन तब तक नहीं किया जाता है जब तक कि उनका गणना नहीं किया जाता है, F # -style कोड में कोई गणना File.WriteAllLinesSeq.map द्वारा उत्पन्न अनुक्रम (सरणी नहीं) के माध्यम से वास्तव में तब तक होती है।

    दूसरे शब्दों में, आपका सी #-स्टाइल संस्करण सभी तारों को उलट रहा है और एक सरणी में उलटा तारों को संग्रहीत कर रहा है, और फिर फ़ाइल में लिखने के लिए सरणी के माध्यम से लूपिंग कर रहा है। एफ # -स्टाइल संस्करण सभी तारों को उलट रहा है और फ़ाइल को अधिक से कम सीधे लिख रहा है। इसका मतलब है कि सी # -स्टाइल कोड पूरी फ़ाइल के माध्यम से तीन बार लूपिंग कर रहा है (सरणी को पढ़ें, रिवर्स किए गए सरणी का निर्माण करें, फ़ाइल में सरणी लिखें), जबकि एफ # -स्टाइल कोड पूरी फाइल के माध्यम से केवल दो बार लूपिंग कर रहा है (सरणी को पढ़ें, लिखें फाइल करने के लिए उलटा लाइनें)।

    आप सभी का सबसे अच्छा प्रदर्शन प्राप्त हैं तो आप File.ReadLines बजाय File.ReadAllLinesSeq.map के साथ संयुक्त प्रयोग किया जाता है - लेकिन अपने आउटपुट फ़ाइल, आपके इनपुट फ़ाइल से अलग हो करने के लिए होगा के रूप में आप उत्पादन के लिए लिख होगी, जबकि अभी भी से पढ़ इनपुट।

    +1

    आह, मैं इसे अब देखता हूं - सी # संस्करण फ़ाइल.WriteAllLines (स्ट्रिंग, स्ट्रिंग []) को कॉल करता है जबकि F # संस्करण फ़ाइल.WriteAllLines (स्ट्रिंग, IENumerable ) कहता है। इसलिए वास्तव में 3 की बजाय केवल 2 loops हैं। यह मेरे दिमाग में नहीं आया कि उस विधि के अन्य अधिभार थे। स्पष्टीकरण के लिए धन्यवाद! – Asik

    1

    Seq.map फ़ॉर्म नियमित लूप पर कई फायदे हैं। यह केवल एक बार समारोह संदर्भ precompute कर सकते हैं; यह परिवर्तनीय असाइनमेंट से बच सकता है; और यह परिणाम सरणी को निर्धारित करने के लिए इनपुट अनुक्रम लंबाई का उपयोग कर सकते हैं।

    +1

    यह बहुत मान्य बिंदुओं की तरह दिखता है, लेकिन मुझे आपका मतलब देखने में कठिनाई है। क्या आप कृपया प्रत्येक बिंदु को विस्तारित और विस्तृत कर सकते हैं? धन्यवाद। – Asik

    संबंधित मुद्दे