2010-03-08 18 views
36

मैं वहाँ प्रदर्शन'...! = शून्य' या 'शून्य! = ....' सर्वश्रेष्ठ प्रदर्शन?

public class Test1 { 

private String value; 

public void notNull(){ 
    if(value != null) { 
    //do something 
    } 
} 

public void nullNot(){ 
if(null != value) { 
    //do something 
} 
} 

} 

जाँच करने के लिए दो तरीकों में लिखा था और जाँच यहाँ

public void notNull(); 
Code: 
Stack=1, Locals=1, Args_size=1 
0: aload_0 
1: getfield #2; //Field value:Ljava/lang/String; 
4: ifnull 7 
7: return 
LineNumberTable: 
line 6: 0 
line 9: 7 

StackMapTable: number_of_entries = 1 
frame_type = 7 /* same */ 


public void nullNot(); 
Code: 
Stack=2, Locals=1, Args_size=1 
0: aconst_null 
1: aload_0 
2: getfield #2; //Field value:Ljava/lang/String; 
5: if_acmpeq 8 
8: return 
LineNumberTable: 
line 12: 0 
line 15: 8 

StackMapTable: number_of_entries = 1 
frame_type = 8 /* same */ 


} 

संकलन के बाद यह बाइट कोड है दो opcodes अगर हालत लागू करने के लिए उपयोग किया जाता है: पहले मामले में यह ifnull- का उपयोग स्टैक के शीर्ष मूल्य की जांच शून्य है-, और दूसरे मामले में यह if_acmpeq- चेक दो शीर्ष मान स्टैक-

से बराबर है, तो क्या यह प्रदर्शन पर प्रभाव डालेगा? (इससे मुझे निष्पादन के साथ-साथ पठनीयता के पहलू में भी अच्छा प्रदर्शन करने में मदद मिलेगी :))

+4

पॉलीजीन का जवाब वह है जिसे आप सुनना चाहिए। लेकिन यदि आप वास्तव में अंतर को समझते हैं, तो प्रत्येक संस्करण को एक अरब गुना या उससे भी अधिक चलाएं, और देखें कि कोई मापनीय अंतर है या नहीं। फिर वापस आओ और हमें इसके बारे में बताता है। –

+0

यह क्यों मायने रखता है, क्या आपका प्रोग्राम केवल 3 लाइन लंबा है कि यह कितना तेज़ या धीमा है कि कथन चलने पर एक अकेलापन कितना धीमा हो? –

+7

जबकि हम इस विषय पर हैं, मैं यह साबित करना चाहता हूं कि उसी पंक्ति पर उद्घाटन घुंघराले ब्रेस डालने के रूप में सशर्त अन्य ब्रेस शैलियों की तुलना में अधिक प्रदर्शनकारी है। –

उत्तर

63

जेनरेटेड बाइटकोड की तुलना करना अधिक अर्थहीन है, क्योंकि अधिकांश अनुकूलन रन टाइम में होता है जेआईटी कंपाइलर। मुझे लगता है कि इस मामले में, या तो अभिव्यक्ति समान रूप से तेज़ है। यदि कोई अंतर है, तो यह नगण्य है।

ऐसा कुछ नहीं है जिसके बारे में आपको चिंता करने की ज़रूरत है। बड़ी तस्वीर अनुकूलन की तलाश करें।

+6

+1 - यह नोट करने के लिए एक बहुत ही महत्वपूर्ण भेद है। – Cam

+4

यह वास्तव में बहुत आसान है: यदि कोई दूसरे की तुलना में तेज़ था, तो माइक्रोसॉफ्ट के कुछ स्मार्ट लोगों ने * पहले ही * कंपाइलर बनाया था या जेआईटी धीमी गति से एक को परिवर्तित कर देगा। –

+0

बाइटकोड पर अच्छा बिंदु, लेकिन आप कैसे जानते हैं कि यह एक बड़ी तस्वीर अनुकूलन नहीं है? यदि आप कम-आबादी वाले डेटा को देख रहे हैं, तो नल की जांच हो सकती है जहां आपका कोड अधिकतर समय बिताता है। –

1

null डालकर पहले एक अतिरिक्त बाइट-कोड उत्पन्न होता प्रतीत होता है, लेकिन इसके अलावा एक प्रदर्शन अंतर नहीं हो सकता है।

व्यक्तिगत रूप से, मैं प्रदर्शन के बारे में चिंता करने के समय तक प्रदर्शन के बारे में चिंता नहीं करता।

मैं notNull() दृष्टिकोण का प्रयोग करेंगे, सिर्फ इसलिए आप अगर आप ! भूल जाते हैं और गलती से टाइप null = value एक संकलक त्रुटि फेंक नहीं है।

+0

लेकिन यदि स्थिति में यदि आप एक ही गलती करते हैं, तो यह संकलित नहीं होगा, यदि मूल्य नहीं है तो बूलियन प्रकार – asela38

+1

मुझे लगता है कि '' मूल्य से अधिक नहीं 'मूल्य टाइप करते समय आपको टाइपो बनाने की अधिक संभावना है ! = शून्य '। – Ponkadoodle

+0

हाँ सहमत हुए, मुझे टाइप प्रकार की जांच करते समय सामान्यता में बात करना था, हालांकि मैंने यह स्पष्ट नहीं किया। धन्यवाद। –

15

गतिशीलता (या स्मृति/जो भी मामला हो) लाभ प्राप्त करने के खर्च पर अनुकूलन न करें, लाभ नगण्य होगा। मुझे लगता है कि !=null आम तौर पर अधिक पठनीय है, इसलिए इसका उपयोग करें।

+0

मैं पठनीयता के बारे में जो कहता हूं उससे सहमत हूं। शून्य निरंतर है, और तुलना के लिए जिसमें स्थिरांक 'चर निरंतर 'सबसे अधिक पठनीय है। – Ponkadoodle

+4

... जब तक आप दाएं से बाएं – CodyBugstein

3

अंतर नगण्य हो जाएगा तो क्या सबसे पठनीय है के साथ जाना (!= null imo)

1

ओह, अगर तुम परम प्रदर्शन के लिए पूछना, अतिरिक्त कक्षा या तरीकों का निर्माण नहीं करतीं। यहां तक ​​कि स्थैतिक तरीकों में थोडा समय लगेगा क्योंकि जावा क्लास लोडर को इसे लोड करने की आवश्यकता है।

तो, जब भी आप यदि किसी वैरिएबल रिक्त है जांच करने की जरूरत है, तो आप सिर्फ यह या तो

if (x == null) 

या

if (null == x) 

सच कहूं मैं प्रदर्शन बोनस मानना ​​द्वारा परीक्षण दो में से एक लेने के लिए अनावश्यक तरीकों को पेश करने के ऊपरी भाग से आसानी से ऑफसेट किया जाता है।

+0

तक पढ़ते हैं, मुझे यकीन है कि इन विधियों को केवल जेनरेट किए गए बाइटकोड में अंतर देखने के लिए एक आसान तरीका के रूप में पेश किया गया है। –

2

मैं पठनीयता के लिए (मूल्य! = शून्य) के साथ रहना चाहता हूं। लेकिन आप हमेशा Assertions का उपयोग कर सकते हैं।

5

सी में आकस्मिक असाइनमेंट से बचने के कड़ी मेहनत के अलावा, बाइनरी ऑपरेटर के बाईं ओर स्थिर रखने के पक्ष में, मुझे बाईं ओर लगातार पढ़ने योग्य लगता है क्योंकि यह महत्वपूर्ण मूल्य रखता है सबसे प्रमुख स्थिति में।

आमतौर पर एक फ़ंक्शन बॉडी केवल कुछ चर का उपयोग करेगा, और यह आम तौर पर संदर्भ के माध्यम से स्पष्ट होता है जो चर के निरीक्षण में है। बाईं ओर निरंतर डालने से, हम switch और case की तुलना में अधिक निकटता से नकल करते हैं: यह चर, एक मिलान मान का चयन करें। बाईं ओर मूल्य को देखते हुए, कोई विशेष स्थिति चुनने पर केंद्रित होता है।

मैं स्कैन

if (var == null) 

मैं रूप में, यह पढ़ते हैं, "हम यहाँ var निरीक्षण कर रहे हैं, और हम समानता के लिए यह तुलना कर रहे हैं, के खिलाफ, आह ... अशक्त।" इसके विपरीत, मैं स्कैन जब

if (null == var) 

मुझे लगता है कि, "अगर एक मूल्य शून्य है हम देख रहे हैं, और ... हाँ, यह var हम निरीक्षण कर रहे हैं।" यह

if (null != var) 

के साथ एक और भी मजबूत मान्यता है जो मेरी आंख तुरंत तुरंत उठाती है।

यह अंतर्ज्ञान आदत की स्थिरता से आता है, जो लिखता है उसे पढ़ने के लिए पसंद करता है, और जो लिखना पसंद करता है उसे लिखना पसंद करता है। कोई भी इसे किसी भी तरह से सीख सकता है, लेकिन यह निष्पक्ष रूप से सच नहीं है क्योंकि अन्य ने यहां जवाब दिया है कि बाईं ओर चर डालने वाला स्पष्ट है। यह इस बात पर निर्भर करता है कि अभिव्यक्ति का कौन सा पहलू सबसे पहले सबसे स्पष्ट होना चाहता है।

बाइटकोड अंतर देखना आकर्षक था। इसे साझा करने के लिए धन्यवाद।

+17

प्रत्येक के अपने अंतर्ज्ञान के लिए ... (हालांकि आप इसके बारे में निश्चित रूप से गलत हैं।)) –

+4

सी में आकस्मिक असाइनमेंट से बचने के 'कड़ी मेहनत की जानकारी लगभग 20 साल पुरानी है, क्योंकि सी कंपाइलर्स अब इसके बारे में चेतावनियां उत्पन्न करते हैं (उन्हें 'लिंट' से प्राप्त करने के बजाय), और यह वास्तव में जावा पर लागू नहीं होता है। – EJP

+0

कि कंपाइलर्स इस बारे में चेतावनी देते हैं अब इस कारण को नहीं बदलता है कि लंबे समय तक प्रोग्रामर ने पहली बार इस शैली को अपनाया है, लेकिन इससे कोई फर्क नहीं पड़ता। मेरा मुद्दा यह है कि इस तरह के आकस्मिक असाइनमेंट से बचने से शैली का एकमात्र लाभ नहीं है, और आज भी इसे अपनाने का एक अच्छा कारण है। पाठक को सबसे ज्यादा रुचि रखने के आधार पर, यह शैली "बेहतर पढ़ सकती है"। – seh

2

इस तरह का मिनट अनुकूलन कंपाइलर का काम है, खासकर जावा जैसी उच्च स्तरीय भाषाओं में।

हालांकि सख्ती से यह यहां प्रासंगिक नहीं है, समय से पहले अनुकूलित न करें!

9

इस तरह के प्रश्नों के साथ, यह जानना मुश्किल है कि JVM कितना स्मार्ट होगा (हालांकि उत्तर "आमतौर पर संभवतः बहुत स्मार्ट है" और यह इस मामले में बहुत संभव लगता है)। लेकिन बस सुनिश्चित करने के लिए, यह परीक्षण:

class Nullcheck { 
    public static class Fooble { } 

    Fooble[] foo = {null , new Fooble(), null , null, 
        new Fooble(), null, null, new Fooble() }; 

    public int testFirst() { 
    int sum = 0; 
    for (int i=0 ; i<1000000000 ; i++) if (foo[i&0x7] != null) sum++; 
    return sum; 
    } 

    public int testSecond() { 
    int sum = 0; 
    for (int i=0 ; i<1000000000 ; i++) if (null != foo[i&0x7]) sum++; 
    return sum; 
    } 

    public void run() { 
    long t0 = System.nanoTime(); 
    int s1 = testFirst(); 
    long t1 = System.nanoTime(); 
    int s2 = testSecond(); 
    long t2 = System.nanoTime(); 
    System.out.printf("Difference=%d; %.3f vs. %.3f ns/loop (diff=%.3f)\n", 
     s2-s1,(t1-t0)*1e-9,(t2-t1)*1e-9,(t0+t2-2*t1)*1e-9); 
    } 

    public static void main(String[] args) { 
    Nullcheck me = new Nullcheck(); 
    for (int i=0 ; i<5 ; i++) me.run(); 
    } 
} 

और मेरे मशीन पर इस पैदावार:

Difference=0; 2.574 vs. 2.583 ns/loop (diff=0.008) 
Difference=0; 2.574 vs. 2.573 ns/loop (diff=-0.001) 
Difference=0; 1.584 vs. 1.582 ns/loop (diff=-0.003) 
Difference=0; 1.582 vs. 1.584 ns/loop (diff=0.002) 
Difference=0; 1.582 vs. 1.582 ns/loop (diff=0.000) 

तो जवाब है: नहीं, सभी में कोई सार्थक फर्क। (और JIT कम्पाइलर दोहराने ने समान संख्या के बाद प्रत्येक तेजी लाने के लिए अतिरिक्त चाल पा सकते हैं।)


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

1

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

-2

बाइट कोड स्रोत कोड का एक साधारण अनुवाद है।

+0

यह पूरी तरह से निर्भर करता है कि आप किस कंपाइलर का उपयोग कर रहे हैं। – EJP

1

दृष्टिकोण से, प्रदर्शन में कोई महत्वपूर्ण अंतर नहीं है।

हालांकि, टाइपो त्रुटियों को पकड़ने के लिए पहले शून्य लिखना उपयोगी है।

उदाहरण के लिए, अगर आप इस कोड लिखने के लिए उपयोग किया जाता है:

if (obj == null) 

गलती से के रूप में लिखा जा सकता है:

if (obj = null) 

संकलक की दृष्टि से, यह ठीक है।

लेकिन, आप के रूप में कोड लिखने के लिए उपयोग किया जाता है:

if (null == obj) 

और गलती की है लिखने के लिए:

if (null = obj) 

संकलक क्या आप जानते हैं आपको लगता है कि लाइन में एक गलती की है दूँगी ।

+2

इस पर पहले ही बहस हो चुकी है, [अन्य उत्तरों पर टिप्पणियां] देखें (http://stackoverflow.com/a/2398688/224132)। आपको यह जवाब समझाने के लिए संपादित करना चाहिए कि आपको यह क्यों लगता है कि यह उपयोगी है, भले ही उन टिप्पणीकारों का कहना है कि यह नहीं है। –

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