2010-02-06 14 views
5

यदि मैं एल्गोरिदम के निष्पादन को समानांतर करना चाहता हूं तो कोड के छोटे भाग क्या हैं जिन्हें मुझे विभाजित करना चाहिए?मुझे किस कोड कोड निष्पादन को समानांतर करना चाहिए?

एक क्लासिक उदाहरण एक सॉर्टिंग एल्गोरिदम है। किस तत्व के आकार या सामान्य निष्पादन समय के लिए यह एकाधिक धागे के बीच सॉर्टिंग को विभाजित करने के लिए समझ में आता है? या एक धागे पर निष्पादन समय से बड़े धागे पर इंतजार करने के लिए ओवरहेड कब होता है?

क्या कोई साधारण नियम हैं? क्या यह ओएस पर निर्भर करता है?

+2

उत्तर देने के लिए कठिन सवाल - वास्तव में समस्या डोमेन और हार्डवेयर बाधाओं पर निर्भर करता है I - क्रमबद्ध करें - आप कितने आइटम सॉर्ट कर रहे हैं और किस हार्डवेयर पर – zebrabox

उत्तर

4

कुंजी नियम केवल "कांटा है जब फोर्किंग ओवरहेड फोर्क के काम की मात्रा से बहुत छोटा है"। चूंकि फोर्किंग ओवरहेड आपके द्वारा उपयोग की जाने वाली विशिष्ट तकनीक की एक संपत्ति है, और इसलिए काम करने का प्रयास भी है, आपको कुछ समझ में यह अनुभवजन्य निर्धारित करना है। इस ट्रेडऑफ का प्रतिनिधित्व करने के लिए आप अपने कोड में निरंतर कुछ थ्रेसहोल्ड ट्यूनिंग स्थिरता के साथ समाप्त हो जाएंगे।

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

कुछ लोग भाग्यशाली हैं और ऐसे बड़े हिस्से मिल सकते हैं; हम उन अधिकांश भौतिकविदों और/या फोरट्रान प्रोग्रामर को बुलाते हैं और वे दुनिया को अलग-अलग टुकड़ों में विभाजित करके प्रेरित समानांतरता का लाभ उठा रहे हैं।

एकमात्र सभ्य इलाज जिसे मैं जानता हूं वह एक शानदार तेजी से फोर्किंग तंत्र का उपयोग करना है, ताकि आप सबसे छोटे व्यावहारिक हिस्सों को पा सकें। दुर्भाग्यवश, समांतरता पुस्तकालयों को ऐसा करने की पेशकश की गई है ... पुस्तकालयों, गतिशील रूप से लागू, गतिशील चालान ओवरहेड के साथ। समांतरता प्राइमेटिव युक्त विशिष्ट पुस्तकालयों में "कांटा" को लागू करने के लिए हजारों चक्रों में 100 से अधिक चक्र होते हैं; यदि आपके काम का हिस्सा 100 मशीन निर्देश है तो यह बुरी खबर है।

मुझे विश्वास है कि इस तरह के तेज फोर्किंग तंत्र प्राप्त करने के लिए, भाषा संकलक को यह जानना है कि आप कांटा कर रहे हैं, उदाहरण के लिए, "कांटा" (हालांकि वर्तनी :-) भाषा में एक कीवर्ड है। फिर संकलक कांटेदार देख सकते हैं, और इसे पूरा करने के लिए समय को कम करने के लिए आवश्यक सब कुछ आवंटित कर सकते हैं, और फोर्किंग (और शामिल) चरणों को प्रबंधित करने के लिए विशेष कोड उत्पन्न कर सकते हैं।

PARLANSE भाषा जिसे मैंने डिज़ाइन किया है, और हम अर्थात् डिजाइन में उपयोग करते हैं, ऐसी एक भाषा है। यह वाक्यविन्यास में एक लिस्प जैसी भाषा है (लेकिन अर्थशास्त्र में नहीं)। इसके समांतरता ऑपरेटर को लिखा गया है "(|| ...)"। आप नीचे दिए गए क्विक्सोर्ट मॉड्यूल में इसे नीचे देख सकते हैं। आप स्पष्ट QuickSortParallelThreshold मान भी देख सकते हैं, जो अनुभवी निर्धारित है। यह क्विक्सोर्ट एक इंटेल x86 सिस्टम पर रैखिक रूप से 8 कोर तक स्केल करता है।

(define QuickSort 
    (module 
    (;; (define Value nu) 
     (compileifthen (~ (defined QuickSortWithParlanseBuiltInOrderingOfNu)) 
      (define QuickSortWithParlanseBuiltInOrderingOfNu ~f) ; use PARLANSE comparison operators 
     )compileifthen 
     (compileifthen (~ (defined QuickSortParallelThreshold)) 
      (define QuickSortParallelThreshold 100) 
     )compileifthen 
     (compileifthen (~ (defined QuickSortThreshold)) 
      (compileifthenelse QuickSortWithParlanseBuiltInOrderingOfNu 
      (define QuickSortThreshold 16) 
      (define QuickSortThreshold 8) 
     )compileifthenelse 
     )compileifthen 
     (compileifthenelse (~ (defined QuickSortWithCompareByReference)) 
      (define QuickSortWithCompareByReference ~f) 
      (compileifthen QuickSortWithParlanseBuiltInOrderingOfNu 
      (define QuickSortWithCompareByReference ~f) 
     )compileifthen 
     )compileifthenelse 
     (define SortRange 
      (action (procedure (structure (compileifthen (~ QuickSortWithParlanseBuiltInOrderingOfNu) 
              (compileifthenelse (~ QuickSortWithCompareByReference) 
              [compare (function (sort integer (range -1 +1)) (structure [value1 Value] [value2 Value]))] 
              [compare (function (sort integer (range -1 +1)) (structure [value1 (reference Value)] [value2 (reference Value)]))] 
             )compileifthenelse 
             )compileifthen 
             [a (reference (array Value 1 dynamic))] 
             [from natural] 
             [to natural] 
          )structure 
       )procedure 
      (local (;; (define quicksort 
         (action (procedure (structure [l integer] [r integer]))) 
         )define 

         (define quicksort 
         (action (procedure (structure [l integer] [r integer])) 
          (ifthenelse (<= (- r l) (coerce integer QuickSortThreshold)) 
          (do [i integer] (++ l) r +1 
           (local (= [exch Value] a:i) 
           (block exit_if_inserted 
            (;; (do [j integer] (-- i) l -1 
             (ifthenelse (compileifthenelse QuickSortWithParlanseBuiltInOrderingOfNu 
                 (> a:j exch) 
                 (compileifthenelse (~ QuickSortWithCompareByReference) 
                 (== (compare a:j exch) +1) 
                 (== (compare (. a:j) (. exch)) +1) 
                 )compileifthenelse 
                )compileifthenelse 
              (= a:(++ j) a:j) 
              (;; (= a:(++ j) exch) 
               (exitblock exit_if_inserted) 
              );; 
             )ifthenelse 
             )do 
             (= a:l exch) 
            );; 
           )block 
           )local 
          )do 
          (local (;; (= [i integer] l) 
             (= [j integer] r) 
             (= [p integer] l) 
             (= [q integer] r) 
             [exch Value] 
            );; 
           (;; 
            `use middle element as pivot': 
            (local (= [m integer] (// (+ l r) +2)) 
             (;; (= exch a:m) 
              (= a:m a:r) 
              (= a:r exch) 
            );; 
            )local 
            `4-way partitioning = < > =': 
            (loop exit_if_partitioned 
             (;; 
             `find element greater than pivot': 
              (loop exit_if_greater_than_found 
              (;; (compileifthenelse QuickSortWithParlanseBuiltInOrderingOfNu 
                (ifthenelse (< a:i a:r) 
                (consume ~t) 
                (ifthenelse (> a:i a:r) 
                 (exitblock exit_if_greater_than_found) 
                 (;; (ifthen (>= i j) 
                  (exitblock exit_if_partitioned) 
                  )ifthen 
                  (= exch a:p) 
                  (= a:p a:i) 
                  (= a:i exch) 
                  (+= p 1) 
                 );; 
                )ifthenelse 
                )ifthenelse 
                (case (compileifthenelse (~ QuickSortWithCompareByReference) 
                  (compare a:i a:r) 
                  (compare (. a:i) (. a:r)) 
                 )compileifthenelse 
                -1 
                 (consume ~t) 
                +1 
                 (exitblock exit_if_greater_than_found) 
                else (;; (ifthen (>= i j) 
                   (exitblock exit_if_partitioned) 
                  )ifthen 
                   (= exch a:p) 
                   (= a:p a:i) 
                   (= a:i exch) 
                   (+= p 1) 
                 );; 
                )case 
               )compileifthenelse 
               (+= i 1) 
              );; 
              )loop 
             `find element less than to pivot': 
              (loop exit_if_less_than_found 
              (;; (-= j 1) 
               (ifthen (>= i j) 
                (exitblock exit_if_partitioned) 
               )ifthen 
               (compileifthenelse QuickSortWithParlanseBuiltInOrderingOfNu 
                (ifthenelse (< a:j a:r) 
                (exitblock exit_if_less_than_found) 
                (ifthenelse (> a:j a:r) 
                 (consume ~t) 
                 (;; (-= q 1) 
                  (= exch a:j) 
                  (= a:j a:q) 
                  (= a:q exch) 
                 );; 
                )ifthenelse 
                )ifthenelse 
                (case (compileifthenelse (~ QuickSortWithCompareByReference) 
                  (compare a:j a:r) 
                  (compare (. a:j) (. a:r)) 
                 )compileifthenelse 
                -1 
                 (exitblock exit_if_less_than_found) 
                +1 
                 (consume ~t) 
                else (;; (-= q 1) 
                   (= exch a:j) 
                   (= a:j a:q) 
                   (= a:q exch) 
                 );; 
                )case 
               )compileifthenelse 
              );; 
              )loop 
             `move found elements to proper partitions': 
              (;; (= exch a:i) 
               (= a:i a:j) 
               (= a:j exch) 
              );; 
             `increment index': 
              (+= i 1) 
            );; 
            )loop 
            `3-way partitioning <=>': 
            (;; 
             `move pivot to final location': 
             (;; (= exch a:i) 
              (= a:i a:r) 
              (= a:r exch) 
              (= j (-- i)) 
              (= i (++ i)) 
             );; 
             `move elements equal to pivot to final locations': 
             (;; (do [k integer] l (-- p) +1 
               (;; (= exch a:k) 
                (= a:k a:j) 
                (= a:j exch) 
                (-= j 1) 
               );; 
              )do 
              (do [k integer] (-- r) q -1 
               (;; (= exch a:i) 
                (= a:i a:k) 
                (= a:k exch) 
                (+= i 1) 
               );; 
              )do 
             );; 
            );; 
            `sort partitions not equal to pivot': 
            (ifthenelse (<= (- r l) (coerce integer QuickSortParallelThreshold)) 
             (;; (quicksort l j) 
              (quicksort i r) 
            );; 
             (|| (quicksort l j) 
              (quicksort i r) 
            )|| 
            )ifthenelse 
           );; 
          )local 
          )ifthenelse 
         )action 
         )define 

        );; 
       (;; (quicksort (coerce integer from) (coerce integer to)) 
        (ifdebug (do [i integer] (coerce integer from) (-- (coerce integer to)) +1 
          (trust (compileifthenelse QuickSortWithParlanseBuiltInOrderingOfNu 
             (<= a:i a:(++ i)) 
             (compileifthenelse (~ QuickSortWithCompareByReference) 
             (<= (compare a:i a:(++ i)) +0) 
             (<= (compare (. a:i) (. a:(++ i))) +0) 
            )compileifthenelse 
            )compileifthenelse 
            `QuickSort:Sort -> The array is not sorted.' 
          )trust 
          )do 
       )ifdebug 
      );; 
      )local 
     )action 
     )define 

     (define Sort 
      (action (procedure (structure (compileifthen (~ QuickSortWithParlanseBuiltInOrderingOfNu) 
              (compileifthenelse (~ QuickSortWithCompareByReference) 
              [compare (function (sort integer (range -1 +1)) (structure [value1 Value] [value2 Value]))] 
              [compare (function (sort integer (range -1 +1)) (structure [value1 (reference Value)] [value2 (reference Value)]))] 
             )compileifthenelse 
             )compileifthen 
             [a (reference (array Value 1 dynamic))] 
          )structure 
       )procedure 
      (compileifthenelse (~ QuickSortWithParlanseBuiltInOrderingOfNu) 
       (SortRange compare a (coerce natural (lowerbound (@ a) 1)) (coerce natural (upperbound (@ a) 1))) 
       (SortRange a (coerce natural (lowerbound (@ a) 1)) (coerce natural (upperbound (@ a) 1))) 
      )compileifthenelse 
     )action 
     )define 

    );; 
)module 
)define 
2

यह अंतर-थ्रेड संचार के ऊपरी हिस्से पर निर्भर करता है। मैंने छवि प्रसंस्करण के साथ ओपनएमपी का परीक्षण किया, और पिक्सल की एक लाइन सुविधाजनक थी, साथ ही अच्छी गति प्रदान करता था। मेरी छवि एक मेगापिक्सेल थी, इसलिए 1000 कार्य थे, जो शायद आज की कईकोर मशीनों को व्यस्त रखने के लिए पर्याप्त से अधिक है। आपको खुद को ऐसी नौकरियों तक सीमित करने की आवश्यकता नहीं है जो एक या दो से अधिक समय लेते हैं। इस उदाहरण में 10 मिलीसेकंड के आदेश की नौकरियों की गतियां स्पष्ट रूप से दिखाई देती हैं।

अब यह एक सुखद एल्गोरिदम था क्योंकि यह रिकर्सिव नहीं था, इसलिए दूसरे पर एक कार्य की कोई निर्भरता नहीं थी, और सभी कार्य स्वचालित रूप से एक ही आकार के थे।

अलग-अलग कार्य आकारों के कारण सॉर्टिंग एल्गोरिदम कठिन होगा। आप इसके साथ प्रयोग करने में सक्षम होना चाहते हैं, और हो सकता है कि एक ऐसे प्रकार का चयन करें जो पैरालाइज करना आसान हो।

1

समवर्ती और समांतर प्रोग्रामिंग में कुछ पाठ्यक्रम लें। सादे पुराने फोर्क & जैसी कई तकनीकों को जानें या "मैनुअल" मल्टीथ्रेडिंग (जावा थ्रेड या पर्थ्रेड), एमपीआई, ओपनएमपी, बीएसपी, शायद सीयूडीए या ओपनसीएल भी। फिर या तो एक विशेषज्ञ बनने का फैसला करें या विशेषज्ञों को कुशल और सही समांतर एल्गोरिदम को डिजाइन और कार्यान्वित करने दें। "समांतर" भाग आसान है, "कुशल" और "सही" भाग नहीं हैं, जब दोनों की आवश्यकता होती है। यहां तक ​​कि जावा समवर्ती वेक्टर संग्रह, विशेषज्ञों द्वारा डिजाइन और कार्यान्वित, पहले संस्करणों में बग से मुक्त नहीं था। जावा मॉडल के पहले संस्करणों में मेमोरी मॉडल की केवल परिभाषा स्पष्ट नहीं थी!

सरल नियम: उपयोग के लिए तैयार के लिए उपयोग घटकों बनाया गया है और विशेषज्ञों द्वारा कार्यान्वित और दोनों शुद्धता और दक्षता अपनी खुद की समानांतर एल्गोरिदम डिजाइनिंग जब तक आप एक विशेषज्ञ हैं प्राप्त करने का प्रयास नहीं करते।

1

इस समस्या को हल करना प्रोग्रामेटिक रूप से समांतर कंप्यूटिंग के पवित्र अंगूरों में से एक है, और कई पुस्तकालय हैं जो विशेष समस्याओं (जैसे डेटा समांतर हास्केल) के लिए इष्टतम समांतरता का अनुमान लगा सकते हैं।

किसी भी तरह, हाथ से ऐसा करने के लिए, आप समझने की जरूरत है:

  • एल्गोरिथ्म है कि आप parallelize करना चाहते हैं (? यह में चलाने योग्य है)
  • डेटा की विशेषताओं, जैसे, आकार, स्थान (डिस्क पर, में स्मृति), आदि
  • हार्डवेयर है कि आप पर चल रहे हैं, उदाहरण के लिए, संख्या कोर, मेमोरी विलंबता, कैश आकार/लाइनों/associavity, आदि
  • दोनों कार्यान्वयन भाषा के सूत्रण मॉडल (coroutines, हरे धागे, ओएस धागे) और ओएस।
  • धागे के बीच स्पॉन्गिंग और संदर्भ-स्विचिंग की लागत।

यह मानते हुए कि एल्गोरिथ्म में चलाने योग्य है, अपने लक्ष्य को धागे की संख्या और डेटा की सापेक्ष हिस्सा आकार, ऐसा है कि आप हार्डवेयर के इष्टतम उपयोग के लिए एक समाधान उत्पन्न करने के लिए कर सकते हैं मिल रहा है।

बहुत सारे प्रयोग किए बिना करना मुश्किल है। इसका पता लगाने का मेरा पसंदीदा तरीका बहुत सारे बेंचमार्क चला रहा है, और निम्नलिखित डेटा के एक या अधिक संयोजनों के प्रदर्शन के रूप में प्रदर्शन डेटा प्राप्त करना:

  • धागे की संख्या।
  • बफर आकार (यदि डेटा रैम में नहीं है) कुछ उचित मूल्य (उदा।, ब्लॉक आकार, पैकेट आकार, कैश आकार इत्यादि) पर बढ़ रहा है
  • वर्ंकिंग खंड आकार (यदि आप डेटा को क्रमशः संसाधित कर सकते हैं)।
  • ओएस या भाषा रनटाइम के लिए विभिन्न ट्यूनिंग knobs।
  • इलाके में सुधार के लिए सीपीयू को धागे पिन करना।
  • आदि

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

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