2012-10-18 30 views
5

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

अगर मैं सिर्फ पाश parallelize करना चाहता था, मैं इस (अत्यधिक सरल) की तरह कुछ लिख सकते हैं:

FILE* f = fopen("output.txt", "w"); 
    omp_lock_t lock; 
    omp_init_lock(&lock); 
    int nIterations = 1000000; 
#pragma omp parallel for 
    for(int thread=0; thread<4; thread++) 
    { 
     int a=0, b=0, c=0; 
     for(int n=thread; n<nIterations; n+=4) 
     { 
      int value = do_computations(&a, &b, &c); 
      omp_set_lock(&lock); 
      fprintf(f, "%d\n", value); 
      omp_unset_lock(&lock); 
     } 
    } 
#pragma omp barrier 
    fclose(f); 
    omp_destroy_lock(&lock); 

इस फ़ाइल में मेरी उत्पादन हो जाता है, लेकिन प्रविष्टियों में से आदेश की गारंटी नहीं दी जाएगी।

मैं निष्पादन को सिंक्रनाइज़ करना चाहता हूं ताकि सभी थ्रेड उनके कार्य कर सकें, फिर मास्टर थ्रेड फ़ाइल में लिखता है, और फिर धागे फिर से शुरू होते हैं। दूसरे शब्दों में, मैं कुछ इस तरह करना चाहते हैं:

#pragma omp parallel for 
     for(int thread=0; thread<4; thread++) 
     { 
      int a=0, b=0, c=0; 
      int values[4]; 
      for(int n=thread; n<nIterations; n+=4) 
      { 
       values[n] = do_computations(&a, &b, &c); 
#pragma omp barrier 
       if(thread == 0) 
       { 
         for(int i=0; i<4; i++) 
         fprintf(f, "%d\n", values[i]); 
       } 
#pragma omp barrier 
      } 
     } 
#pragma omp barrier 

छोड़कर, कुछ अबोध्य कारण के लिए, इस OpenMP विनिर्देश द्वारा निषिद्ध है।

या मैं

#pragma omp parallel for 
     for(int thread=0; thread<4; thread++) 
     { 
      int a=0, b=0, c=0; 
      for(int n=thread; n<nIterations; n+=4) 
      { 
       int value = do_computations(&a, &b, &c); 
#pragma omp ordered 
       { 
        fprintf(f, "%d\n", value); 
       } 
      } 
     } 
    #pragma omp barrier 
     fclose(f); 

की कोशिश कर सकते लेकिन वह, या तो काम नहीं करेगा क्योंकि "के साथ एक पाश की एक यात्रा एक निर्माण के लिए ... एक से अधिक आदेश दिया निर्देश पर अमल नहीं करना चाहिए।"

मैं कोड को एक लूप के रूप में फिर से लिखना नहीं चाहता हूं और मैं लूप का आदान-प्रदान नहीं करना चाहता हूं।

क्या अन्य थ्रेडिंग/सिंक्रनाइज़ेशन टूल के बिना ओपनएमपी के साथ ऐसा करने का कोई साफ तरीका है?

+0

आपके कोड को चलाने वाले आर्किटेक्चर/ऑपरेटिंग सिस्टम क्या है? – Raj

+0

क्या आप – Raj

+0

के समानांतर के बजाय '#pragma omp समानांतर' का उपयोग करने का प्रयास कर सकते हैं क्या 'do_computations' वास्तव में तीन' 0' पास हो गया है? मुझे लगता है कि 'do_computations' एक शुद्ध कार्य नहीं है (यानी इसका साइड इफेक्ट्स है)। यदि ऐसा है, तो 'do_computations' के दुष्प्रभाव क्या हैं? क्या होता है जब समानांतर में 'do_computations' को दो कॉल निष्पादित किए जाते हैं? मुझे बहुत संदेह है कि आप उन्हें समानांतर में निष्पादित करने के साथ भी दूर हो सकते हैं (इस धारणा के आधार पर कि साइड इफेक्ट्स हैं, और इसलिए आदेश जिसमें निष्पादन * मामलों * होते हैं)। - या आप कोड को overimplifying कर रहे हैं? हो सकता है कि आपको कुछ ऐसा साझा करना चाहिए जो आपके वास्तविक पाश को बेहतर ढंग से प्रदर्शित करता हो? – ArjunShankar

उत्तर

3

आप दो चीजें करने की कोशिश कर रहे हैं - एक गणना और आईओ। गणना समानांतर हो सकती है, लेकिन आईओ जरूरी है कि धारावाहिक हो। लेकिन आईओ को गणना के रूप में एक ही लूप में डालकर, आप गणना पर क्रमबद्धीकरण को भी मजबूर कर रहे हैं, जो कोई समझ नहीं आता है।

आप सभी गणना, फिर आईओ करने से बेहतर होगा। सीरियल में यह लगभग निश्चित रूप से तेज़ होगा, खासकर यदि आप fprintfs पर लूप के बजाय बाइनरी में डेटा को एक बड़े हिस्से में लिख सकते हैं।

FILE* f = fopen("output.txt", "w"); 
    const int nIterations = 1000000; 
    int values[nIterations]; 

#pragma omp parallel for 
    for(int n=0; n<niterations; n++) 
    { 
     int a=0, b=0, c=0; 
     values[n] = do_computations(&a, &b, &c); 
    } 

    for (int n=0; n<niterations; n++) 
     fprintf(f,"%d\n", values[n]); 

    fclose(f); 

इसके लिए अधिक स्मृति की आवश्यकता है, लेकिन फिर गति बनाम स्मृति एक आम व्यापार-बंद है। कि तालमेल के चरम काम नहीं करते हैं, तो आप हमेशा समायोज्य आकार मात्रा में गणना कर सकते हैं:

const int nIterations = 1000000; 
    const int chunkSize = 10000; 
    int values[chunkSize]; 
    int chunkNum = 0; 
    int chunkLeft = chunkSize; 

    for (int start = 0; start < nIterations; start+= chunkSize) { 

     if (start+chunkSize > nIterations) chunkLeft = nIterations - start; 

    #pragma omp parallel for 
     for(int n=start; n<start+chunkLeft; n++) 
     { 
      int a=0, b=0, c=0; 
      values[n-start] = do_computations(&a, &b, &c); 
     } 

     for (int n=0; n<chunkLeft; n++) 
      fprintf(f,"%d\n", values[n]); 

    } 
    fclose(f); 
+0

हम उस परिस्थिति के बारे में बात कर रहे हैं जहां कंप्यूटेशंस और I/O को ओवरलैप करना आवश्यक है। निश्चित रूप से, एक दूसरे को करना आमतौर पर आसान होता है। जब तक आपके पास 12 घंटे की गणना नहीं होती है, तब तक बिजली की गड़बड़ी होती है और लूप को पूरा करने के लिए राम में सभी परिणामों को बफर किया जा रहा है। – user434507

+0

यह बहुत अच्छा है, लेकिन आप संचार और गणना को ओवरलैप नहीं कर रहे हैं, आप बस अपनी गणना को क्रमबद्ध कर रहे हैं, यहां तक ​​कि एक कर्सर प्रोफाइलिंग भी प्रदर्शित होगी। यदि आप दोनों को ओवरलैप करना चाहते हैं, तो एक अलग आईओ कार्य बनाएं और आउटपुट बफर करने के लिए निर्माता/उपभोक्ता दृष्टिकोण का उपयोग करें। –

+0

मैं गणना को क्रमबद्ध नहीं कर रहा हूं, I/O समय के 0.01% लेता है, शेष समय धागे समानांतर में चलते हैं। आप इस पर विचार कर रहे हैं। मूल प्रश्न में मैंने जो लिखा वह बिल्कुल वही है जो मुझे चाहिए। – user434507

0

मैं एक समाधान पहले से ही पूर्व उत्तर में मौजूद नहीं का प्रस्ताव करने की कोशिश करेंगे:

#include <stdio.h> 
#include <assert.h> 
#include <unistd.h> 

#define NITER 100 

int main() { 

    FILE * f = fopen("output.bin", "w+"); 

#pragma omp parallel 
    { 
#pragma omp for schedule(runtime) 
    for (int ii = 0; ii < NITER; ++ii) {  
     sleep(1); // Simulate computation 
     printf("%d\n",ii); // Just to be convinced that the loop is not evaluated in serial order 
#pragma omp critical (FILEWRITE) 
     { 
    fseek (f ,sizeof(ii)*ii,SEEK_SET); 
    fwrite(&ii,sizeof(ii),1,f); 
     }  
    } 
    } 

    // Check serially that the file is written in the right order 
    fseek(f,0,SEEK_SET); 
    int value = -1; 
    for (int ii = 0; ii < NITER; ++ii) {   
    fread (&value,sizeof(ii),1,f);  
    assert(value == ii); 
    } 

    fclose(f); 
    return 0; 
} 

यह मामला तभी लागू होता है जब प्रत्येक खंड में एक बहुत अच्छी तरह से परिभाषित आकार होता है ताकि यह पता चल सके कि आप किस कंप्यूटिंग को कंप्यूटिंग कर रहे हैं, तो आप फ़ाइल की शुरुआत से अपना ऑफसेट प्राप्त कर सकते हैं।

उस ने कहा, कोड स्निपेट में आप प्रदान कर रहे हैं कई त्रुटियां हैं जो सुझाव देती हैं कि आपको ओपनएमपी की मूलभूत समीक्षा की जानी चाहिए। उदाहरण के लिए:

#pragma omp parallel for 
    for(int thread=0; thread<4; thread++) 
    { // No need to unroll the loop as OpenMP runtime 
     // map iterations on threads based on the scheduling policy 
     int a=0, b=0, c=0; 
     for(int n=thread; n<nIterations; n+=4) 
     { 
      int value = do_computations(&a, &b, &c); 
      // No need to use lock, when a critical construct suffices 
      omp_set_lock(&lock); 
      fprintf(f, "%d\n", value); 
      omp_unset_lock(&lock); 
     } 
    } // Implicit barrier at the end of the parallel for 
#pragma omp barrier 
// Why a barrier when there is only one thread? 
+0

क्या लॉक पर महत्वपूर्ण का कोई फायदा है? गंभीर थोड़ा छोटा कोड देता है, लेकिन दोनों विकल्पों को समान फैशन में काम करना चाहिए। – user434507

+0

@ user434507 बड़ा अंतर फ्रेक का उपयोग करने के लिए कार्यरत निर्माण से बचने के लिए 'आदेश दिया गया' घोषित करने के लिए है (जो, मेरे अनुभव के आधार पर, एक बड़ी मंदी पैदा कर सकता है)। इसके अलावा, '#pragma omp critical' का उपयोग करके' omp.h' पर अनावश्यक निर्भरता से बचें ताकि यदि आप बाइनरी के एक सीरियल संस्करण को संकलित करना चाहते हैं तो आपको अपने स्रोतों को '#ifdef _OPENMP' से भरना नहीं है। – Massimiliano

+0

हां, दुर्भाग्यवश, यह एक दिलचस्प दृष्टिकोण है, अगर मैं पहले से ही खंड आकार को नहीं जानता तो मदद नहीं करता है। विंडोज़ में, आपको omp.h को शामिल करना होगा या आपको लिंकर त्रुटियां मिलेंगी। – user434507

0

पार्टी के लिए देर हो चुकी है, लेकिन अगर किसी को यहाँ जवाब की तलाश में ठोकर, तुम क्या जरूरत है #pragma omp single है, लेकिन साथ ही @ जोनाथन-dursi के साथ चर्चा देखें।