2014-08-31 5 views
12

मैं स्कैला और जावा संस्करणों के लगभग समान, कार्यान्वयन के बीच कुछ प्रदर्शन विसंगति में भाग गया। मैं जावा संस्करण देख रहा हूं जो स्कैला संस्करण से 68% तेज है। ऐसा क्यों होता है इसके बारे में कोई विचार है?स्कैला बनाम जावा प्रदर्शन (हैशसेट और बिग्राम पीढ़ी)

जावा संस्करण:

public class Util { 
public static Set <String> toBigramsJava(String s1) { 
    Set <String> nx = new HashSet <String>(); 
    for (int i = 0; i < s1.length() - 1; i++) { 
     char x1 = s1.charAt(i); 
     char x2 = s1.charAt(i + 1); 
     String tmp = "" + x1 + x2; 
     nx.add(tmp); 
    } 
    return nx; 
} 

}

स्काला संस्करण:

object Util { 
def toBigramsScala(str: String): scala.collection.mutable.Set[String] = { 
    val hash: scala.collection.mutable.Set[String] = scala.collection.mutable.HashSet[String]() 
    for (i <-0 to str.length - 2) { 
     val x1 = str.charAt(i) 
     val x2 = str.charAt(i + 1) 
     val tmp = "" + x1 + x2 
     hash.add(tmp) 
    } 
    return hash 
} 

}

टेस्ट परिणाम:

scala> Util.time(for(i<-1 to 1000000) {Util.toBigramsScala("test test abc de")}) 17:00:05.034 [info] Something took: 1985ms

Util.time(for(i<-1 to 1000000) {Util.toBigramsJava("test test abc de")}) 17:01:51.597 [info] Something took: 623ms

सिस्टम:

मैं 4 कोर और 8gig रैम के साथ Ubuntu 14.04 पर इस भाग गया,। जावा संस्करण 1.7.0_45, स्कैला संस्करण 2.10.2।

मेरे blog पर कुछ और जानकारी है।

+2

हालांकि यह कोई प्रश्न नहीं है ... आप इसे प्रश्न और उत्तर के मिलान के सेट में संशोधित कर सकते हैं। –

+1

मेरा सुझाव है कि आप अंतर देखने के लिए बाइट कोड देखें। –

+1

क्या यह 'लूप्स' के लिए जावा का अनुकूलन हो सकता है जो स्कैला में मौजूद नहीं है, क्योंकि उनके पास स्कैला में कुछ विशिष्टताएं हैं? वे दो विधियां वास्तव में समान लगती हैं। इसके अलावा, यदि आप scala.collection.mutable.HashSet को java.util.HashSet के साथ प्रतिस्थापित करते हैं तो क्या होता है? – Dici

उत्तर

10

मैं इस स्केला संस्करण

object Util { 
    def toBigramsScala(str: String) = { 
    val hash = scala.collection.mutable.Set.empty[String] 
    var i: Int = 0 
    while (i < str.length - 1) { 
     val x1 = str.charAt(i) 
     val x2 = str.charAt(i + 1) 
     val tmp = new StringBuilder().append(x1).append(x2).toString() 
     hash.add(tmp) 
     i += 1 
    } 
    hash 
    } 
} 

साथ मोटे तौर पर एक ही परिणाम रहा Function0 पर) कॉल लागू करने के लिए (के रूप में लागू स्केला में पाश विधि है जो है megamorphic विधि कॉल (JVM/से महंगा के लिए याद के रूप में मिल गया है जेआईटी दृष्टिकोण देखें)। इसके अलावा संभवतः जावैक द्वारा बनाई गई कुछ स्ट्रिंग कॉन्सटेनेशन ऑप्टिमाइज़ेशन।

मैंने उत्पन्न बाइट कोड को देखने के साथ अपनी धारणाओं की जांच नहीं की, लेकिन के साथ बदलकर और स्ट्रिंगबिल्डर के साथ स्ट्रिंग कॉन्सटेनेशन ने अंतर नगण्य बना दिया।

Time for Java Version: 451 millis 
Time for Scala Version: 589 millis 
3

मैंने एक समान परीक्षण किया है।

यहाँ वर्ग हैं:

जावा

public class JavaApp { 
    public static void main(String[] args) { 
     String s1 = args[0]; 
     java.util.Set <String> nx = new java.util.HashSet<>(); 
     for (int i = 0; i < s1.length() - 1; i++) { 
      char x1 = s1.charAt(i); 
      char x2 = s1.charAt(i + 1); 
      String tmp = "" + x1 + x2; 
      nx.add(tmp); 
     } 
     System.out.println(nx.toString()); 
    } 
} 

स्काला

object ScalaApp { 
    def main(args:Array[String]): Unit = { 
     var s1 = args(0) 
     val hash: scala.collection.mutable.Set[String] = scala.collection.mutable.HashSet[String]() 
     for (i <-0 to s1.length - 2) { 
      val x1 = s1.charAt(i) 
      val x2 = s1.charAt(i + 1) 
      val tmp = "" + x1 + x2 
      hash.add(tmp) 
     } 
     println(hash.toString()) 
    } 
} 

संकलनकर्ता और रनटाइम संस्करण

Javac javac 1.8.0_20-ईए

Java जावा संस्करण "1.8.0_20-ईए"

Scalac स्काला संकलक संस्करण 2.11.0 - कॉपीराइट 2002-2013, दीप/EPFL

Scala स्काला कोड धावक संस्करण 2.11.0 - कॉपीराइट 2002-2013 , एलएएमपी/ईपीएफएल

स्कैला भी धीमा है। Scala संस्करण पर एक नज़र डालने पर, यह दो अज्ञात वर्ग बनाता है।

एक चीज जो कुछ समय ले सकती है auto boxingchar पर for लूप में परिवर्तनीय है।

44: iload_2 
    45: invokestatic #61     // Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character; 
    48: invokevirtual #55     // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 
    51: iload_3 
    52: invokestatic #61     // Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character; 
    55: invokevirtual #55     // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 

लेकिन यह सब कुछ समझा नहीं है।

4

के लिए-comprehensions हमेशा धीमी एक while पाश या explained here के रूप में पूंछ प्रत्यावर्तन का उपयोग कर तो कर रहे हैं।

आपके उदाहरण में दूसरी समस्या String एस का संगतता है। स्कैला scala.collection.mutable.StringBuilder का उपयोग करेगा जिसमें कुछ प्रदर्शन समस्याएं हैं (उदाहरण के लिए यह आपके char से Char उदाहरणों को बॉक्स करेगा) जैसा कि अन्य उत्तरों में उल्लिखित है।

पूंछ-पुनरावर्ती विधि के लिए समझ को बदलना और java.lang.StringBuilder का उपयोग करके आप स्कैला और जावा दोनों में अधिकतर परिणाम प्राप्त करेंगे (मेरी मशीन स्कैला वास्तव में कुछ मिलीसेकंड तेज है)।

0

स्कैला कोड को आगे बढ़ाने के कुछ तरीके हैं।

  1. इसके बजाय एक StringBuilder का उपयोग कर के, हम बजाय एक 2 चरित्र चार सरणी का उपयोग
  2. इसके बजाय अस्थायी Vals x1 और x2 बनाने के बजाय, हम सिर्फ सीधे चार सरणी को लिखने
  3. हम तो स्ट्रिंग के चार [का उपयोग] हैशसेट
  4. के अंदर रखने के लिए स्ट्रिंग बनाने के लिए कन्स्ट्रक्टर हम लूप समाप्ति को एक परिवर्तनीय अधिकतम में निकालते हैं, केवल अगर JIT इसे अनुकूलित करने से चूक जाए।

    object Util { 
        def toBigramsScala(str: String) = { 
         val hash = scala.collection.mutable.HashSet.empty[String] 
         val charArray = new Array[Char](2) 
         var i = 0 
         val max = str.length - 1 
         while (i < max) { 
         charArray(0) = str.charAt(i) 
         charArray(1) = str.charAt(i + 1) 
         hash.add(new String(charArray)) 
         i += 1 
         } 
         hash 
        } 
        } 
    
उन परिवर्तनों के साथ

, मैं जावा और स्काला कोड के बीच एक ही रन टाइम प्राप्त करने में सक्षम था। आश्चर्य की बात है (कम से कम इस उदाहरण में), java.util.HashSet ने mutable पर कोई प्रदर्शन लाभ नहीं दिया। हैशसेट। निष्पक्षता में, हम इन सभी अनुकूलन को जावा कोड में भी लागू कर सकते हैं,

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