10

का उपयोग नहीं कर रहा प्रतीत होता है मैं एफ # में कुछ कम्प्यूटेशनल गहन काम कर रहा हूं। Array.Parallel.map जैसे फ़ंक्शंस जो नेट टास्क समांतर लाइब्रेरी का उपयोग करते हैं, वास्तव में काफी कम प्रयास के लिए मेरे कोड को तेजी से बढ़ा दिया है।एफ # PSeq.iter सभी कोर

हालांकि, स्मृति चिंताओं के कारण, मैंने अपने कोड का एक खंड रीमेड किया ताकि इसे अनुक्रम अभिव्यक्ति के अंदर आलसी मूल्यांकन किया जा सके (इसका मतलब है कि मुझे कम जानकारी को स्टोर करना और पास करना है)। जब यह मूल्यांकन करने के लिए समय आ गया मैं प्रयोग किया है:

// processor and memory intensive task, results are not stored 
let calculations : seq<Calculation> = seq { ...yield one thing at a time... } 

// extract results from calculations for summary data 
PSeq.iter someFuncToExtractResults results 

बजाय:

// processor and memory intensive task, storing these results is an unnecessary task 
let calculations : Calculation[] = ...do all the things... 

// extract results from calculations for summary data 
Array.Parallel.map someFuncToExtractResults calculations 

Array.Parallel कार्यों में से किसी का उपयोग करते समय मैं स्पष्ट रूप से गियर में अपने कंप्यूटर लात पर सभी कोर देख सकते हैं (~ 100% सीपीयू उपयोग)। हालांकि अतिरिक्त स्मृति की आवश्यकता है कि कार्यक्रम कभी खत्म नहीं हुआ।

जब मैं प्रोग्राम चलाता हूं तो PSeq.iter संस्करण के साथ, केवल 8% CPU उपयोग (और न्यूनतम RAM उपयोग) होता है।

तो: क्या कोई कारण है कि पीएसईक संस्करण इतनी धीमी गति से चलता है? क्या यह आलसी मूल्यांकन की वजह से है? क्या कुछ जादू "समानांतर" सामान है जो मुझे याद आ रही है?

धन्यवाद,

अन्य संसाधन, दोनों के स्रोत कोड कार्यान्वयन (वे .NET में अलग समानांतर पुस्तकालयों का उपयोग करने लगते हैं):

https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/array.fs

https://github.com/fsharp/powerpack/blob/master/src/FSharp.PowerPack.Parallel.Seq/pseq.fs

संपादित करें: अधिक जोड़ा गया कोड उदाहरण और विवरण के लिए विवरण

कोड:

  • Seq

    // processor and memory intensive task, results are not stored 
    let calculations : seq<Calculation> = 
        seq { 
         for index in 0..data.length-1 do 
          yield calculationFunc data.[index] 
        } 
    
    // extract results from calculations for summary data (different module) 
    PSeq.iter someFuncToExtractResults results 
    
  • सरणी

    // processor and memory intensive task, storing these results is an unnecessary task 
    let calculations : Calculation[] = 
        Array.Parallel.map calculationFunc data 
    
    // extract results from calculations for summary data (different module) 
    Array.Parallel.map someFuncToExtractResults calculations 
    

विवरण:

  • Intermediat भंडारण ई सरणी संस्करण 10 मिनट से कम समय में (जहां तक ​​यह क्रैश से पहले हो जाता है) चलाता है लेकिन क्रैश होने से पहले ~ 70 जीबी रैम का उपयोग करता है (64 जीबी भौतिक, बाकी पेजेड)
  • सीईसी संस्करण 34 मिनट से अधिक लेता है और रैम के एक अंश का उपयोग करता है (केवल 30 जीबी)
  • एक ~ अरब मूल्य है जो मैं गणना कर रहा हूं। इसलिए एक बिलियन युगल (प्रत्येक 64 बिट्स पर) = 7.4505806 जीबी। डेटा के अधिक जटिल रूप हैं ... और कुछ अनावश्यक प्रतियां जिन्हें मैं साफ कर रहा हूं इसलिए मौजूदा भारी रैम उपयोग।
  • हाँ वास्तुकला महान नहीं, आलसी मूल्यांकन मुझे के पहले भाग में छोटे टुकड़ों में प्रोग्राम और/या डेटा को बैच का अनुकूलन करने के
  • एक छोटे डाटासेट के साथ
  • , कोड उत्पादन ही दोनों मात्रा का प्रयास कर रहा है परिणाम है।
  • @ पैड, मैंने आपके द्वारा सुझाए गए प्रयासों की कोशिश की, पीएसईक।जब गणना [] को खिलाया जाता है तो यह ठीक से काम करता है (सभी कोर सक्रिय), लेकिन अभी भी रैम का मामला है (यह अंततः दुर्घटनाग्रस्त हो गया है)
  • कोड और गणना भाग दोनों का सारांश भाग सीपीयू गहन है (मुख्य रूप से क्योंकि बड़े डेटा सेट का)
  • Seq संस्करण के साथ
  • मैं सिर्फ parallelize करने एक बार
+1

आलसी मूल्यांकन समानांतर निष्पादन के साथ अच्छा नहीं खेलता है। निष्पक्ष होने के लिए, 'गणना [] '' PSeq.iter' और' Array.Parallel.map' 'को पास करें। 'गणना' और 'someFuncToExtractResults' के अधिक विवरण किए बिना कारण बताना असंभव है। – pad

+0

सुझाव के लिए धन्यवाद, मैंने कोशिश की और पीएसईक आलसी सीक्यू के बजाय सरणी दिए जाने पर अच्छी तरह से व्यवहार करता है ... हालांकि यह रैम समस्या –

उत्तर

5

आपकी नवीन सूचना के आधार पर, मैं सिर्फ प्रासंगिक हिस्से के लिए मेरा उत्तर को छोटा कर रहा हूँ करना है। तुम बस के बजाय के लिए आपके वर्तमान के इस की जरूरत है:

let result = data |> PSeq.map (calculationFunc >> someFuncToExtractResults) 

और यह एक ही काम करेंगे कि क्या आप PSeq.map या Array.Parallel.map का उपयोग करें।

हालांकि, आपकी असली समस्या हल नहीं होने वाली है। इस समस्या को इस प्रकार बताया जा सकता है: जब 100% CPU उपयोग प्राप्त करने के लिए समानांतर कार्य की वांछित डिग्री तक पहुंच जाती है, तो प्रक्रियाओं का समर्थन करने के लिए पर्याप्त स्मृति नहीं होती है।

क्या आप देख सकते हैं कि यह कैसे हल नहीं किया जाएगा? आप या तो अनुक्रमिक रूप से चीजों को संसाधित कर सकते हैं (कम CPU कुशल, लेकिन स्मृति कुशल) या आप समानांतर में चीजों को संसाधित कर सकते हैं (अधिक CPU कुशल, लेकिन स्मृति से बाहर चला जाता है)।

विकल्प तो हैं:

  1. बदलें समानांतरवाद की डिग्री कुछ करने के लिए इन कार्यों के द्वारा प्रयोग किया जा सकता है कि अपनी स्मृति झटका नहीं होगा:

    let result = data 
          |> PSeq.withDegreeOfParallelism 2 
          |> PSeq.map (calculationFunc >> someFuncToExtractResults) 
    
  2. परिवर्तन के लिए अंतर्निहित तर्क calculationFunc >> someFuncToExtractResults ताकि यह एक ऐसा कार्य है जो परिणामों के माध्यम से डेटा को अधिक कुशल और स्ट्रीम करता है। अधिक जानकारी के बिना, यह देखना आसान नहीं है कि यह कैसे किया जा सकता है। लेकिन आंतरिक रूप से, निश्चित रूप से कुछ आलसी लोडिंग संभव हो सकता है।

+0

हल नहीं करता है, दोनों गहन हैं, मुझे यकीन नहीं है कि आपका दूसरा मतलब क्या है बिंदु, क्या आप कृपया विस्तृत कर सकते हैं? –

+0

@ एंथनीट्रस्किंगर: मैंने आपके द्वारा प्रदान की गई अतिरिक्त जानकारी के आधार पर कुछ महत्वपूर्ण अपडेट किए हैं। ध्यान दें कि अगर आप एल्गोरिदम बदलना नहीं चाहते हैं तो आपको कहीं भी एक व्यापार चुनना होगा (आपको एल्गोरिदम बदलने के बिना 100% सीपीयू और कुशल स्मृति नहीं मिलेगी)। यदि आप एल्गोरिदम बदल सकते हैं, तो, मेरा जवाब देखें। – yamen

3

Array.Parallel.map हुड के नीचे Parallel.For का उपयोग करता है, जबकि PSeqPLINQ चारों ओर एक पतली आवरण है। लेकिन वे अलग-अलग व्यवहार का कारण यहां हैं PSeq.iter के लिए पर्याप्त वर्कलोड नहीं है जब seq<Calculation> अनुक्रमिक और नए परिणाम देने में बहुत धीमी है।

मुझे इंटरमीडिएट सीक या सरणी का उपयोग करने का विचार नहीं मिलता है।

// Should use PSeq.map to match with Array.Parallel.map 
PSeq.map (calculationFunc >> someFuncToExtractResults) data 

और

Array.Parallel.map (calculationFunc >> someFuncToExtractResults) data 

आप लेने वाली बहुत सी स्मृति से बचने और एक ही स्थान पर जो होता है में गहन गणना है: मान लीजिए data इनपुट सरणी होने के लिए, एक ही स्थान पर सभी गणना चलती जाने का रास्ता है समांतर निष्पादन में बेहतर दक्षता के लिए।