2013-08-21 4 views
13

मेरा सहकर्मी और मैं कार्य करने में व्यतीत समय के संबंध में रेखांकित कार्यों की तुलना में काम करने के लिए लैम्ब्डा में गुजरते समय सी # कार्यों की गति की तुलना कर रहा था। हमने पाया कि सी # चयन फ़ंक्शन (उदाहरण के लिए) के लिए लैम्ब्डा प्रक्षेपण में गुज़रने पर आपको लागत लग गई थी और यह देखना चाहता था कि एफ # में एक ही समस्या थी, या यदि यह कुछ अलग था।योग या राशि से तेज़ क्यों कम हो जाता है?

हमारे मूल उद्देश्य के बावजूद, हम उस चीज़ पर ठोकर खाए जिसे हम समझ नहीं सकते। निम्न उदाहरण में हम एक सूची 3 अलग अलग तरीकों

  1. योग कम
  2. योग
  3. SumBy

module fs 

open NUnit.Framework 
open FsUnit 
open System 
open System.Diagnostics; 

[<Test>] 
let sumTest() = 
    let nums = [0..1000] 

    let repeat = 100000 

    let stopWatch = new Stopwatch() 

    stopWatch.Start() 

    let sumsReduce = 
     [ 
      for i in [0..repeat] do 
       yield List.reduce (+) nums 
     ] 

    Console.WriteLine("reduce = {0} - Time = {1}", List.head sumsReduce, stopWatch.Elapsed.TotalSeconds); 
    stopWatch.Restart() 

    let sumsSum = 
     [ 
      for i in [0..repeat] do 
       yield List.sum nums 
     ] 

    Console.WriteLine("sum = {0} - Time = {1}", List.head sumsSum, stopWatch.Elapsed.TotalSeconds); 
    stopWatch.Restart() 


    let sumsSumBy = 
     [ 
      for i in [0..repeat] do 
       yield List.sumBy id nums 
     ] 

    Console.WriteLine("sumBy = {0} - Time = {1}", List.head sumsSumBy, stopWatch.Elapsed.TotalSeconds); 
    stopWatch.Restart() 

यह करने के लिए उत्पादन की तरह दिखता है:

reduce = 500500 - Time = 0.2725156 
sum = 500500 - Time = 1.1183165 
sumBy = 500500 - Time = 1.1126781 

तो यहां बड़े विजेता को स्पष्ट रूप से कम करना है। decompilation में, मैं देख सकता हूँ कम

[Serializable] 
internal class sumsReduce\u004021\u002D1 : OptimizedClosures.FSharpFunc<int, int, int> 
{ 
    internal sumsReduce\u004021\u002D1() 
    { 
    base.\u002Ector(); 
    } 

    public override int Invoke(int x, int y) 
    { 
    return x + y; 
    } 
} 

नीचे उबला हुआ हो जाता है लेकिन मैं एक मुश्किल समय पता लगाना क्या योग और sumBy कर रहे हैं हो रही है कि। समय विसंगति कहां से है?


वर्तमान उत्तर ने सुझाव दिया कि कम 5 गुना तेज है क्योंकि मूल रूप से मैं एक अनचेक ऑपरेटर को कम कर रहा था। हालांकि, परीक्षण अद्यतन करने (Checked मॉड्यूल से) एक जाँच ऑपरेटर का उपयोग करने के लिए और मैं अभी भी एक ही परिणाम प्राप्त

let sumsReduce = 
     [ 
      for i in [0..repeat] do 
       yield List.reduce (Checked.(+)) nums 
     ] 

सूचना समय विसंगति अभी भी

reduce = 500500 - Time = 0.274697 
sum = 500500 - Time = 1.1126796 
sumBy = 500500 - Time = 1.1370642 
+0

मैं यह मानने के लिए बहुत इच्छुक हूं कि @ildjarn इसे सही मिला। जांच अंकगणित को चीजों को धीमा करना है। –

+0

@OnorioCatenacci, मैंने चेक arithemtic के साथ परीक्षण चलाया और इससे कोई फर्क नहीं पड़ता – devshorts

उत्तर

16

योग और SumBy एक प्रगणक का उपयोग करें:

while e.MoveNext() do 
     acc <- Checked.(+) acc e.Current 
    acc 

जबकि कम करने एक अनुकूलित बंद के साथ एक पुनरावर्ती पाश का उपयोग करता है: (कम करने का उपयोग करता है कवर के तहत गुना - गुना च सिर पूंछ)

let fold<'T,'State> f (s:'State) (list: 'T list) = 
     match list with 
     | [] -> s 
     | _ -> 
      let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f) 
      let rec loop s xs = 
       match xs with 
       | [] -> s 
       | h::t -> loop (f.Invoke(s,h)) t 
      loop s list 

अनुकूलित बंद करने का उपयोग अक्सर प्रदर्शन को बढ़ावा देता है।

+1

हम्म को अद्यतन करने जा रहा हूं जो अधिक समझ में आता है, लेकिन, उस मामले में गलती में SumLoop फ़ंक्शन SumEnum से तेज़ी से चलना चाहिए। https://gist.github.com/faisalmansoor/6301115 लेकिन, List.reduce विधि की तरह SumLoop को उबालता है, जबकि List.Sum से SumEnum। कोई विचार? –

+1

मुझे लगता है कि यह सूची ट्रैवर्सल है जो अंतर को बनाता है, न कि 'ऑप्टिमाइज्डक्लोजर'। 'ऑप्टिमाइज्डक्लोजर' और एन्युमरेटर का उपयोग प्रदर्शन में बहुत कम वृद्धि प्रदान करता है, लेकिन एक रिकर्सिव फ़ंक्शन में 'चेकड। (+)' का उपयोग करके 'List.Reduce' जितना तेज़ होता है। –

+0

सच है, अनुकूलित बंद करने से अत्यधिक करीबी कार्यों आदि के साथ एक अंतर आता है। – 7sharp9

7

sum और sumBy उपयोग अंकगणित जाँच से मौजूद है, लेकिन आप अनचेक ऑपरेटर + से reduce पर जा रहे हैं - सेब से बिल्कुल सेब नहीं।

+0

अच्छा, यह समझ में आता है। – devshorts

+1

जानकारी के लिए धन्यवाद ठीक है, इसलिए मैंने एक नया परीक्षण किया और मुझे ऐसा नहीं लगता है। मैं प्रश्न – devshorts

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