2016-12-11 9 views
5

मैं एल्गोरिदम को तेज़ करने और जावा चुनने के लिए समांतर प्रोग्रामिंग सीखना चाहता था।
मैंने सरणी में long पूर्णांक को संक्षेप में दो कार्यों को लिखा - सरणी के माध्यम से एक सरल पुनरावृत्ति, भागों में भागों को विभाजित करने और अलग-अलग धागे में भागों को जोड़ना।जावा एकाधिक थ्रेड बहुत छोटे परफॉर्मेंस लाभ

मुझे दो धागे का उपयोग करके लगभग 2x गति के तार्किक होने की उम्मीद है। हालांकि, मुझे जो मिला है वह केवल 24% तेज है। इसके अलावा, अधिक धागे का उपयोग करके, मुझे दो धागे से अधिक सुधार (शायद कम 1%) नहीं मिलता है। मुझे पता है कि थ्रेड सृजन/ओवरहेड में शामिल होना चाहिए, लेकिन मुझे लगता है कि यह इतना बड़ा नहीं होना चाहिए।

क्या आप कृपया समझा सकते हैं, मुझे क्या याद आ रहा है या कोड में त्रुटि कहां है?

import java.util.concurrent.ThreadLocalRandom; 


public class ParallelTest { 


public static long sum1 (long[] num, int a, int b) { 
    long r = 0; 
    while (a < b) { 
     r += num[a]; 
     ++a; 
    } 
    return r; 
} 

public static class SumThread extends Thread { 
    private long num[]; 
    private long r; 
    private int a, b; 

    public SumThread (long[] num, int a, int b) { 
     super(); 
     this.num = num; 
     this.a = a; 
     this.b = b; 
    } 

    @Override 
    public void run() { 
     r = ParallelTest.sum1(num, a, b); 
    } 

    public long getSum() { 
     return r; 
    } 
} 


public static long sum2 (long[] num, int a, int b, int threadCnt) throws InterruptedException { 
    SumThread[] th = new SumThread[threadCnt]; 
    int i = 0, c = (b - a + threadCnt - 1)/threadCnt; 

    for (;;) { 
     int a2 = a + c; 
     if (a2 > b) { 
      a2 = b; 
     } 
     th[i] = new SumThread(num, a, a2); 
     th[i].start(); 
     if (a2 == b) { 
      break; 
     } 
     a = a2; 
     ++i; 
    } 

    for (i = 0; i < threadCnt; ++i) { 
     th[i].join(); 
    } 
    long r = 0; 
    for (i = 0; i < threadCnt; ++i) { 
     r += th[i].getSum(); 
    } 
    return r; 
} 

public static void main(String[] args) throws InterruptedException { 
    final int N = 230000000; 
    long[] num = new long[N]; 

    for (int i = 0; i < N; ++i) { 
     num[i] = ThreadLocalRandom.current().nextLong(1, 9999); 
    } 

    // System.out.println(Runtime.getRuntime().availableProcessors()); 

    long timestamp = System.nanoTime(); 
    System.out.println(sum1(num, 0, num.length)); 
    System.out.println(System.nanoTime() - timestamp); 

    for (int n = 2; n <= 4; ++n) { 
     timestamp = System.nanoTime(); 
     System.out.println(sum2(num, 0, num.length, n)); 
     System.out.println(System.nanoTime() - timestamp); 
    } 


} 
} 

संपादित करें: यहाँ कोड है मैं 4 कोर (8 धागे) के साथ i7 प्रोसेसर है। आउटपुट कोड द्वारा दिए गए है:

1149914787860 
175689196 
1149914787860 
149224086 
1149914787860 
147709988 
1149914787860 
138243999 

उत्तर

3

कार्यक्रम शायद मुख्य स्मृति बैंडविड्थ सिर्फ दो धागे के साथ सीमित है, के रूप में यह एक छोटे से पाश, कि लगभग जितनी जल्दी राम प्रोसेसर के लिए डेटा की आपूर्ति कर सकते डेटा को हासिल करेगा है।

+0

इसका मतलब है, अगर मेरे पास लूप में अधिक CPU-गहन कार्य था, तो मेरे पास अधिक धागे के साथ बेहतर perfomance लाभ होगा? – Somnium

+0

@ सोमनियम - सही। – rcgldr

3

मैं एक नंबर कारणों से आप के रूप में ज्यादा speedup के रूप में आप उम्मीद कर रहे हैं नहीं मिल सकता है के बारे में सोच सकते हैं।

  1. धागा निर्माण ओवरहेड्स पर्याप्त हैं। थ्रेड start() एक महंगा ऑपरेशन है, जिसमें थ्रेड स्टैक और उसके "रेड-जोन" आवंटित करने के लिए कई सिस्कोल होते हैं और फिर मूल धागा बनाते हैं।

  2. एन धागे सभी एक ही समय में शुरू नहीं होंगे। इसका मतलब है कि गणना के समानांतर भाग को पूरा करने का समय अंतिम धागे का अंत-समय होगा - पहली बार स्टार्ट-टाइम। यह उस समय से अधिक होगा जब एक धागे काम के अपने हिस्से को करने के लिए लेता है। (एन -1 बार थ्रेड निर्माण समय ...)

  3. एन थ्रेड (मूल रूप से) सरणी के एन विघटन खंडों का एक धारावाहिक स्कैन कर रहे हैं। यह मेमोरी बैंडविड्थ गहन है, और जिस तरह से आप स्कैनिंग कर रहे हैं इसका मतलब है कि मेमोरी कैश अप्रभावी होने जा रहे हैं। इसलिए, एक अच्छा मौका है कि प्रदर्शन आपके सिस्टम के मुख्य मेमोरी हार्डवेयर की गति और बैंडविड्थ द्वारा सीमित है।

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