सी, क्लोजर, पायथन, रूबी, स्काला और अन्य में एक बेंचमार्क की व्याख्या [बंद]


91

अस्वीकरण

मुझे पता है कि कृत्रिम बेंचमार्क बुराई हैं। वे केवल बहुत विशिष्ट संकीर्ण स्थिति के लिए परिणाम दिखा सकते हैं। मैं यह नहीं मानता कि कुछ बेवकूफ बेंच के कारण एक भाषा दूसरे से बेहतर है। हालांकि मुझे आश्चर्य है कि परिणाम इतने अलग क्यों हैं। कृपया मेरे प्रश्नों को नीचे देखें।

गणित बेंचमार्क विवरण

बेंचमार्क सरल गणित की गणना है, जो कि अभाज्य संख्याओं की जोड़ियों को खोजने के लिए है, जो 6 से भिन्न होती है (जिसे सेक्सी प्राइम कहा जाता है ) जैसे कि 100 से कम सेक्सी प्राइम निम्न होंगे:(5 11) (7 13) (11 17) (13 19) (17 23) (23 29) (31 37) (37 43) (41 47) (47 53) (53 59) (61 67) (67 73) (73 79) (83 89) (97 103)

परिणाम तालिका

तालिका में: सेकंड में गणना समय चल रहा है: सभी को छोड़कर फैक्टर वर्चुअलबॉक्स में चल रहा था (डेबियन अस्थिर amd64 अतिथि, विंडोज 7 x 64 होस्ट) CPU: AMD A4-3305M

  Sexy primes up to:        10k      20k      30k      100k               

  Bash                    58.00   200.00     [*1]      [*1]

  C                        0.20     0.65     1.42     15.00

  Clojure1.4               4.12     8.32    16.00    137.93

  Clojure1.4 (optimized)   0.95     1.82     2.30     16.00

  Factor                    n/a      n/a    15.00    180.00

  Python2.7                1.49     5.20    11.00       119     

  Ruby1.8                  5.10    18.32    40.48    377.00

  Ruby1.9.3                1.36     5.73    10.48    106.00

  Scala2.9.2               0.93     1.41     2.73     20.84

  Scala2.9.2 (optimized)   0.32     0.79     1.46     12.01

[* 1] - मैं कल्पना करने से डरता हूं कि इसमें कितना समय लगेगा

कोड लिस्टिंग

सी:

int isprime(int x) {
  int i;
  for (i = 2; i < x; ++i)
    if (x%i == 0) return 0;
  return 1;
}

void findprimes(int m) {
  int i;
  for ( i = 11; i < m; ++i)
    if (isprime(i) && isprime(i-6))
      printf("%d %d\n", i-6, i);
}

main() {
    findprimes(10*1000);
}

माणिक:

def is_prime?(n)
  (2...n).all?{|m| n%m != 0 }
end

def sexy_primes(x)
  (9..x).map do |i|
    [i-6, i]
  end.select do |j|
    j.all?{|j| is_prime? j}
  end
end

a = Time.now
p sexy_primes(10*1000)
b = Time.now
puts "#{(b-a)*1000} mils"

स्काला:

def isPrime(n: Int) =
  (2 until n) forall { n % _ != 0 }

def sexyPrimes(n: Int) = 
  (11 to n) map { i => List(i-6, i) } filter { _ forall(isPrime(_)) }

val a = System.currentTimeMillis()
println(sexyPrimes(100*1000))
val b = System.currentTimeMillis()
println((b-a).toString + " mils")

स्काला ने opimized isPrime( क्लोजर ऑप्टिमाइज़ेशन में समान विचार):

import scala.annotation.tailrec

@tailrec // Not required, but will warn if optimization doesn't work
def isPrime(n: Int, i: Int = 2): Boolean = 
  if (i == n) true 
  else if (n % i != 0) isPrime(n, i + 1)
  else false

Clojure:

(defn is-prime? [n]
  (every? #(> (mod n %) 0)
    (range 2 n)))

(defn sexy-primes [m]
  (for [x (range 11 (inc m))
        :let [z (list (- x 6) x)]
        :when (every? #(is-prime? %) z)]
      z))

(let [a (System/currentTimeMillis)]
  (println (sexy-primes (* 10 1000)))
  (let [b (System/currentTimeMillis)]
    (println (- b a) "mils")))

क्लोजर अनुकूलित is-prime?:

(defn ^:static is-prime? [^long n]
  (loop [i (long 2)] 
    (if (= (rem n i) 0)
      false
      (if (>= (inc i) n) true (recur (inc i))))))

अजगर

import time as time_

def is_prime(n):
  return all((n%j > 0) for j in xrange(2, n))

def primes_below(x):
  return [[j-6, j] for j in xrange(9, x+1) if is_prime(j) and is_prime(j-6)]

a = int(round(time_.time() * 1000))
print(primes_below(10*1000))
b = int(round(time_.time() * 1000))
print(str((b-a)) + " mils")

फ़ैक्टर

MEMO:: prime? ( n -- ? )
n 1 - 2 [a,b] [ n swap mod 0 > ] all? ;

MEMO: sexyprimes ( n n -- r r )
[a,b] [ prime? ] filter [ 6 + ] map [ prime? ] filter dup [ 6 - ] map ;

5 10 1000 * sexyprimes . .

बैश (zsh):

#!/usr/bin/zsh
function prime {
  for (( i = 2; i < $1; i++ )); do
    if [[ $[$1%i] == 0 ]]; then
      echo 1
      exit
    fi
  done
  echo 0
}

function sexy-primes {
  for (( i = 9; i <= $1; i++ )); do
    j=$[i-6]
    if [[ $(prime $i) == 0 && $(prime $j) == 0 ]]; then
      echo $j $i
    fi
  done
}

sexy-primes 10000

प्रशन

  1. स्काला इतना तेज क्यों है? क्या यह स्थैतिक टाइपिंग के कारण है ? या यह सिर्फ जेवीएम का बहुत कुशलता से उपयोग कर रहा है?
  2. रूबी और पायथन के बीच इतना बड़ा अंतर क्यों? मुझे लगा कि ये दोनों कुछ अलग नहीं हैं। शायद मेरा कोड गलत है। कृपया मुझे ज्ञान दो! धन्यवाद। UPD हाँ, यह मेरे कोड में त्रुटि थी। पायथन और रूबी 1.9 बहुत समान हैं।
  3. रूबी संस्करणों के बीच उत्पादकता में वास्तव में प्रभावशाली छलांग।
  4. क्या मैं प्रकार की घोषणाओं को जोड़कर क्लोजर कोड का अनुकूलन कर सकता हूं? क्या यह मदद करेगा?

6
@mgilson वास्तव में ऊपर है, sqrt(n)लेकिन यह गणना करने के लिए कुछ समय ले सकता है। साथ ही आपका सी कोड उन प्रिंटों को प्रिंट करता है जैसा कि वह उन्हें पाता है, जबकि आपकी अन्य भाषाएं उन्हें सूचियों में गणना करती हैं और फिर उन्हें प्रिंट करती हैं। जबकि सी सबसे तेजी से है, आप इसे तेजी से प्राप्त करने में सक्षम हो सकते हैं।
रस

2
(और निश्चित रूप से चलनी ऑफ एराटोस्थनीज .. लेकिन यह माइक्रो बेंचमार्क बहुत अधिक

2
मैंने अपना Go संस्करण और आपका C संस्करण दोनों ही चलाए (जो एक जैसे लगते हैं) और मुझे व्यावहारिक रूप से उन दोनों में समान गति मिली। मैंने केवल 100k संस्करण की कोशिश की C: 2.723s Go: 2.743s:।
सेबेस्टियन ग्रिग्नोली

3
आपको sqrtइस चेक के लिए गणना करने की आवश्यकता नहीं है । आप के iरूप में के वर्ग की गणना कर सकते हैंfor (i = 2; i * i <= x; ++i) ...
ivant

3
मेरा सुझाव है कि आप स्कैला के isPrimeसाथ एनोटेट @tailrecकरें, यह सुनिश्चित करने के लिए कि आप पूंछ पुनरावृत्ति का उपयोग कर रहे हैं। गलत तरीके से कुछ करना आसान है जो पूंछ पुनरावृत्ति को रोकता है, और यह एनोटेशन आपको चेतावनी देता है कि यदि ऐसा होता है।
डैनियल सी। सोबरल

जवाबों:


30

कठिन उत्तर:

  1. स्काला की स्थैतिक टाइपिंग यहां काफी मदद कर रही है - इसका मतलब है कि यह JVM को बहुत अधिक अतिरिक्त प्रयास के बिना कुशलतापूर्वक उपयोग करता है।
  2. मुझे रूबी / पायथन अंतर पर बिल्कुल यकीन नहीं है, लेकिन मुझे संदेह है कि (2...n).all?फ़ंक्शन is-prime?रूबी (EDIT) में काफी अच्छी तरह से अनुकूलित होने की संभावना है: ऐसा लगता है कि यह वास्तव में मामला है, अधिक विस्तार के लिए जूलियन का जवाब देखें ...)
  3. रूबी 1.9.3 बहुत बेहतर अनुकूलित है
  4. क्लोजर कोड निश्चित रूप से बहुत तेज हो सकता है! जबकि क्लोजर डिफ़ॉल्ट रूप से गतिशील होता है, आप जरूरत पड़ने पर कई मामलों में स्केल / शुद्ध जावा गति के करीब जाने के लिए टाइप संकेत, आदिम गणित आदि का उपयोग कर सकते हैं।

क्लोजर कोड में सबसे महत्वपूर्ण अनुकूलन टाइप प्राइमिटिव मैथ्स का उपयोग करना होगा is-prime?, जैसे कुछ:

(set! *unchecked-math* true) ;; at top of file to avoid using BigIntegers

(defn ^:static is-prime? [^long n]
  (loop [i (long 2)] 
    (if (zero? (mod n i))
      false
      (if (>= (inc i) n) true (recur (inc i))))))

इस सुधार के साथ, मैं क्लोजर को 0.6k सेकेंड्स में 10k पूरा कर रहा हूं (यानी आपकी सूची में दूसरा सबसे तेज, स्काला को हराकर)

पुनश्च नोट करें कि आपके पास कुछ मामलों में अपने बेंचमार्क के अंदर प्रिंटिंग कोड है - एक अच्छा विचार नहीं है क्योंकि यह परिणामों को विकृत करेगा, खासकर अगर printपहली बार किसी फ़ंक्शन का उपयोग करते हुए IO सबसिस्टम के आरंभीकरण का कारण बनता है या ऐसा कुछ!


2
मुझे नहीं लगता कि रूबी और पायथन के बारे में थोड़ा सच है, लेकिन +1 अन्यथा ..

टाइपिंग में कोई औसत दर्जे का स्थिर परिणाम नहीं दिखा, लेकिन आपका नया is-prime?2x सुधार दिखाता है। ;)
3

अगर कोई अनियंत्रित-आधुनिक होता तो क्या इसे और तेज नहीं बनाया जा सकता था?
हेंडकेगॉन

1
@ हेंडकेगन - शायद! यह निश्चित नहीं है कि यह वर्तमान क्लोजर कंपाइलर द्वारा कितनी अच्छी तरह से अनुकूलित किया गया है, इसमें सुधार की गुंजाइश है। क्लोजर 1.4 निश्चित रूप से इस तरह के सामान के लिए सामान्य रूप से बहुत मदद करता है, 1.5 शायद बेहतर भी होगा।
मिकेरा

1
(zero? (mod n i))से अधिक तेज़ होना चाहिए(= (mod n i) 0)
जोनास

23

यहां एक समान बुनियादी एल्गोरिदम का उपयोग करते हुए एक तेज़ क्लोजर संस्करण है:

(set! *unchecked-math* true)

(defn is-prime? [^long n]
  (loop [i 2]
    (if (zero? (unchecked-remainder-int n i))
      false
      (if (>= (inc i) n)
        true
        (recur (inc i))))))

(defn sexy-primes [m]
  (for [x (range 11 (inc m))
        :when (and (is-prime? x) (is-prime? (- x 6)))]
    [(- x 6) x]))

यह मेरी मशीन पर आपके मूल से लगभग 20x तेज चलता है। और यहां एक संस्करण है जो 1.5 में नए रीड्यूसर लाइब्रेरी का लाभ उठाता है (जावा 7 या जेएसआर 166 की आवश्यकता होती है):

(require '[clojure.core.reducers :as r]) ;'

(defn sexy-primes [m]
  (->> (vec (range 11 (inc m)))
       (r/filter #(and (is-prime? %) (is-prime? (- % 6))))
       (r/map #(list (- % 6) %))
       (r/fold (fn ([] []) ([a b] (into a b))) conj)))

यह आपके मूल से लगभग 40x तेज चलता है। मेरी मशीन पर, यह 1.5 सेकंड में 100k है।


2
का उपयोग करना unchecked-remainder-intया बस remके बजाय mod4x प्रदर्शन वृद्धि करने के लिए स्थिर टाइपिंग परिणामों के साथ। अच्छा!
डिफ्ल्ट

22

मैं सिर्फ # 2 का उत्तर दूंगा, क्योंकि यह एकमात्र ऐसा है जिसे मैंने कुछ भी कहने के लिए बुद्धिमानी से प्राप्त किया है, लेकिन अपने पायथन कोड के लिए, आप एक मध्यवर्ती सूची बना रहे हैं is_prime, जबकि आप रूबी .mapमें अपने उपयोग कर रहे हैं allजो कि बस बार-बार दोहराना।

यदि आप अपना परिवर्तन करते is_primeहैं:

def is_prime(n):
    return all((n%j > 0) for j in range(2, n))

वे बराबर हैं।

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

संपादित करें: बहुत मूर्खतापूर्ण होने के बिना, पायथन कोड जैसा दिखता है:

import time

def is_prime(n):
    return all(n % j for j in xrange(2, n))

def primes_below(x):
    return [(j-6, j) for j in xrange(9, x + 1) if is_prime(j) and is_prime(j-6)]

a = int(round(time.time() * 1000))
print(primes_below(10*1000))
b = int(round(time.time() * 1000))
print(str((b-a)) + " mils")

जो बहुत अधिक नहीं बदलता है, इसे मेरे लिए 1.5s पर रखता है, और, अतिरिक्त मूर्खतापूर्ण होने के कारण, इसे PyP के साथ चलाने से इसे 10K के लिए .3s और 100K के लिए 21s पर रख दिया जाता है।


1
जनरेटर यहां एक बड़ा अंतर बनाता है क्योंकि यह फ़ंक्शन को पहले False(अच्छे कैच) पर जमानत की अनुमति देता है ।
mgilson

मैं वास्तव में उन्हें PyPy में सुन्न होने के लिए आगे देख रहा हूँ ... यह भयानक होने जा रहा है।
mgilson

क्या आप कृपया अपना जवाब PyPy में चलाएंगे? मैं उत्सुक हूं कि यह कितना तेज होगा।
स्टीवेहा जूल 25'12

1
तुम दोनों के बारे में पूरी तरह से सही बात कर रहे हैं और xrange! मैंने तय कर लिया है और अब पायथन और रूबी बराबर परिणाम दिखाते हैं।
डिफॉल्ट

1
@steveha मैं ऐसा तभी करूँगा जब आप अभी बाहर जाने का वादा करेंगे और खुद PyPy डाउनलोड करेंगे :)! pypy.org/download.html में सभी सामान्य OS के लिए बायनेरी हैं , और आपके पैकेज मैनेजर के पास निस्संदेह है। वैसे भी, आपके बेंचमार्क के लिए, जैसा कि lru_cache2.7 पर एक यादृच्छिक कार्यान्वयन के रूप में मिला, 2.3 में 100K चलता है।
जूलियन

16

आप अपनी isPrimeविधि को संशोधित करके स्कैला को बहुत तेज़ बना सकते हैं

  def isPrime(n: Int, i: Int = 2): Boolean = 
    if (i == n) true 
    else if (n % i != 0) isPrime(n, i + 1)
    else false

संक्षिप्त के रूप में काफी नहीं है, लेकिन कार्यक्रम 40% समय में चलता है!

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

यह भी देखें: स्काला में समझने और समझने के लिए अनुकूलन कैसे करें?


2
2x सुधार। और अच्छा लिंक!
डिफॉल्ट जूल

btw इस विधि शरीर के समान है i == n || n % i != 0 && isPrime(n, i + 1), जो छोटा है, भले ही पढ़ने के लिए थोड़ा कठिन है
लुइगी प्लिंज

1
आपको @tailrecएनोटेशन जोड़ना चाहिए था , यह सुनिश्चित करने के लिए कि यह अनुकूलन करेगा।
डैनियल सी। सोबरल

8

यहाँ मेरा स्कैला संस्करण समानांतर और नो-पैरेलल दोनों में है, बस मज़े के लिए: (मेरी दोहरी कोर गणना में, समानांतर संस्करण में 335ms लगते हैं जबकि नो-पैरेलल संस्करण में 655ms लगते हैं)

object SexyPrimes {
  def isPrime(n: Int): Boolean = 
    (2 to math.sqrt(n).toInt).forall{ n%_ != 0 }

  def isSexyPrime(n: Int): Boolean = isPrime(n) && isPrime(n-6)

  def findPrimesPar(n: Int) {
    for(k <- (11 to n).par)
      if(isSexyPrime(k)) printf("%d %d\n",k-6,k)
  }

  def findPrimes(n: Int) {
    for(k <- 11 to n)
      if(isSexyPrime(k)) printf("%d %d\n",k-6,k)
  }


  def timeOf(call : =>Unit) {
    val start = System.currentTimeMillis
    call
    val end = System.currentTimeMillis
    println((end-start)+" mils")
  }

  def main(args: Array[String]) {
    timeOf(findPrimes(100*1000))
    println("------------------------")
    timeOf(findPrimesPar(100*1000))
  }
}

EDIT: एमिल एच के सुझाव के अनुसार , मैंने IO और jvm वार्मअप के प्रभावों से बचने के लिए अपना कोड बदल दिया है:

परिणाम मेरी गणना में पता चलता है:

सूची (3432, 1934, 3261, 1716, 3229, 1654, 3214, 1700)

object SexyPrimes {
  def isPrime(n: Int): Boolean = 
    (2 to math.sqrt(n).toInt).forall{ n%_ != 0 }

  def isSexyPrime(n: Int): Boolean = isPrime(n) && isPrime(n-6)

  def findPrimesPar(n: Int) {
    for(k <- (11 to n).par)
      if(isSexyPrime(k)) ()//printf("%d %d\n",k-6,k)
  }

  def findPrimes(n: Int) {
    for(k <- 11 to n)
      if(isSexyPrime(k)) ()//printf("%d %d\n",k-6,k)
  }


  def timeOf(call : =>Unit): Long = {
    val start = System.currentTimeMillis
    call
    val end = System.currentTimeMillis
    end - start 
  }

  def main(args: Array[String]) {
    val xs = timeOf(findPrimes(1000*1000))::timeOf(findPrimesPar(1000*1000))::
             timeOf(findPrimes(1000*1000))::timeOf(findPrimesPar(1000*1000))::
             timeOf(findPrimes(1000*1000))::timeOf(findPrimesPar(1000*1000))::
             timeOf(findPrimes(1000*1000))::timeOf(findPrimesPar(1000*1000))::Nil
    println(xs)
  }
}

1
क्या कोड jvm वार्मअप से प्रभावित होता है? उदाहरण के isSexyPrimeलिए (अधिक) से अनुकूलित किया जा सकता है जब से बुलाया जाता है findPrimesParऔर जब से नहीं बुलाया जाता है तोfindPrimes
Emil H

@EmilH मेला काफी मैंने io और jvm वार्मअप के प्रभाव से बचने के लिए अपना कोड बदल दिया है।
पूर्वीन

केवल sqrt (n) तक जाना एक अच्छा अनुकूलन है, लेकिन अब आप एक अलग एल्गोरिदम बेंचमार्किंग कर रहे हैं।
लुइगी प्लिंज

7

बेंचमार्क पर कभी ध्यान न दें; समस्या ने मुझे दिलचस्पी दी और मैंने कुछ तेज़ मोड़ दिए। यह lru_cacheडेकोरेटर का उपयोग करता है , जो एक फ़ंक्शन को याद करता है; इसलिए जब हम कॉल करते हैं तो is_prime(i-6)हम मूल रूप से उस प्राइम चेक को मुफ्त में प्राप्त करते हैं। यह परिवर्तन कार्य को लगभग आधे में काट देता है। इसके अलावा, हम range()कॉल को केवल विषम संख्याओं के माध्यम से कर सकते हैं , काम को फिर से लगभग आधा कर सकते हैं।

http://en.wikipedia.org/wiki/Memoization

http://docs.python.org/dev/library/functools.html

इसे पाने के लिए पायथन 3.2 या नए की आवश्यकता होती है lru_cache, लेकिन यदि आप एक पायथन नुस्खा प्रदान करते हैं जो पुराने पायथन के साथ काम कर सकता है lru_cache। यदि आप पायथन 2.x का उपयोग कर रहे हैं तो आपको xrange()इसके बजाय वास्तव में उपयोग करना चाहिए range()

http://code.activestate.com/recipes/577479-simple-caching-decorator/

from functools import lru_cache
import time as time_

@lru_cache()
def is_prime(n):
    return n%2 and all(n%i for i in range(3, n, 2))

def primes_below(x):
    return [(i-6, i) for i in range(9, x+1, 2) if is_prime(i) and is_prime(i-6)]

correct100 = [(5, 11), (7, 13), (11, 17), (13, 19), (17, 23), (23, 29),
        (31, 37), (37, 43), (41, 47), (47, 53), (53, 59), (61, 67), (67, 73),
        (73, 79), (83, 89)]
assert(primes_below(100) == correct100)

a = time_.time()
print(primes_below(30*1000))
b = time_.time()

elapsed = b - a
print("{} msec".format(round(elapsed * 1000)))

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

मेरे लैपटॉप पर (विशेष कुछ भी नहीं; प्रोसेसर 1.5 गीगाहर्ट्ज़ एएमडी ट्यूरियन II "K625" है) इस संस्करण ने 8 सेकंड के भीतर 100K के लिए एक उत्तर का उत्पादन किया।

from functools import lru_cache
import math
import time as time_

known_primes = set([2, 3, 5, 7])

@lru_cache(maxsize=128)
def is_prime(n):
    last = math.ceil(math.sqrt(n))
    flag = n%2 and all(n%x for x in known_primes if x <= last)
    if flag:
        known_primes.add(n)
    return flag

def primes_below(x):
    return [(i-6, i) for i in range(9, x+1, 2) if is_prime(i) and is_prime(i-6)]

correct100 = [(5, 11), (7, 13), (11, 17), (13, 19), (17, 23), (23, 29),
        (31, 37), (37, 43), (41, 47), (47, 53), (53, 59), (61, 67), (67, 73),
        (73, 79), (83, 89)]
assert(primes_below(100) == correct100)

a = time_.time()
print(primes_below(100*1000))
b = time_.time()

elapsed = b - a
print("{} msec".format(round(elapsed * 1000)))

उपरोक्त कोड पाइथन, रूबी आदि में लिखना बहुत आसान है, लेकिन सी में दर्द अधिक होगा।

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


lru_cacheनिश्चित रूप से निफ्टी है। समस्या के कुछ वर्गों के लिए, जैसे कि क्रमिक फाइबोनैचि संख्याओं को उत्पन्न करना, यह फ़ंक्शन पर उस एक लाइन डेकोरेटर को जोड़कर एक विशाल गति प्रदान कर सकता है! यहाँ कि कवर एक रेमंड Hettinger बात करने के लिए एक लिंक भी है lru_cache। में 26 मिनट के बारे में blip.tv/pycon-us-videos-2009-2010-2011/...
steveha

3
Lru_cache का उपयोग करके, आप वास्तव में कच्चे कोड के बजाय दूसरे एल्गोरिथ्म का उपयोग करते हैं। इसलिए प्रदर्शन एल्गोरिदम के बारे में है, लेकिन भाषा ही नहीं।
ईस्ट्सुन

1
@ एतसुन - मुझे समझ में नहीं आता कि आपका क्या मतलब है। lru_cacheएक गणना को दोहराने से बचा जाता है जो हाल ही में किया गया था, और वह सब है; मैं नहीं देखता कि यह कैसे "वास्तव में हमें [आईएनजी] एक और एल्गोरिथ्म" है। और पायथन धीमे होने से पीड़ित है, लेकिन ठंडा सामान जैसे होने से लाभ lru_cache; मुझे किसी भाषा के लाभकारी हिस्सों का उपयोग करने में कुछ भी गलत नहीं दिखता है। और मैंने कहा कि किसी को भी अन्य लोगों के समान परिवर्तन किए बिना अन्य भाषाओं के विरुद्ध मेरे उत्तर के रन समय की तुलना नहीं करनी चाहिए। तो, मुझे समझ नहीं आ रहा है कि आपका क्या मतलब है।
स्टीवेहा जूल 25'12

@ इस्टुनन सही है, लेकिन दूसरी तरफ उच्च स्तर की भाषा की सुविधा की अनुमति दी जानी चाहिए जब तक कि अतिरिक्त बाधाएं नहीं दी जाती हैं। lru_cache गति के लिए स्मृति का त्याग करेगा, और एल्गोरिथम जटिलता को समायोजित करेगा।
मैट जॉइनर

2
यदि आप एक और एल्गोरिथ्म का उपयोग करते हैं तो आप चलनी की इरेटोस्थनीज की कोशिश कर सकते हैं। पायथन संस्करण ने 0.03सेकंड ( 30एमएस) के तहत 100K के लिए एक उत्तर का उत्पादन किया
जूल

7

फोरट्रान मत भूलना! (ज्यादातर मजाक करते हुए, लेकिन मैं सी के समान प्रदर्शन की उम्मीद करूंगा)। विस्मयादिबोधक अंकों के साथ बयान वैकल्पिक हैं, लेकिन अच्छी शैली है। ( !फोरट्रान 90 में एक टिप्पणी चरित्र है)

logical function isprime(n)
IMPLICIT NONE !
integer :: n,i
do i=2,n
   if(mod(n,i).eq.0)) return .false.
enddo
return .true.
end

subroutine findprimes(m)
IMPLICIT NONE !
integer :: m,i
logical, external :: isprime

do i=11,m
   if(isprime(i) .and. isprime(i-6))then
      write(*,*) i-6,i
   endif
enddo
end

program main
findprimes(10*1000)
end

6

मैं सी संस्करण के लिए सबसे स्पष्ट अनुकूलन में से कुछ करने के लिए विरोध नहीं कर सका, जिसने 100k परीक्षण किया अब मेरी मशीन पर 0.3 s (प्रश्न में सी संस्करण की तुलना में 5 गुना तेज, दोनों MSVC 2010 / ऑक्स के साथ संकलित) ।

int isprime( int x )
{
    int i, n;
    for( i = 3, n = x >> 1; i <= n; i += 2 )
        if( x % i == 0 )
            return 0;
    return 1;
}

void findprimes( int m )
{
    int i, s = 3; // s is bitmask of primes in last 3 odd numbers
    for( i = 11; i < m; i += 2, s >>= 1 ) {
        if( isprime( i ) ) {
            if( s & 1 )
                printf( "%d %d\n", i - 6, i );
            s |= 1 << 3;
        }
    }
}

main() {
    findprimes( 10 * 1000 );
}

यहाँ जावा में समान कार्यान्वयन है:

public class prime
{
    private static boolean isprime( final int x )
    {
        for( int i = 3, n = x >> 1; i <= n; i += 2 )
            if( x % i == 0 )
                return false;
        return true;
    }

    private static void findprimes( final int m )
    {
        int s = 3; // s is bitmask of primes in last 3 odd numbers
        for( int i = 11; i < m; i += 2, s >>= 1 ) {
            if( isprime( i ) ) {
                if( ( s & 1 ) != 0 )
                    print( i );
                s |= 1 << 3;
            }
        }
    }

    private static void print( int i )
    {
        System.out.println( ( i - 6 ) + " " + i );
    }

    public static void main( String[] args )
    {
        // findprimes( 300 * 1000 ); // for some JIT training
        long time = System.nanoTime();
        findprimes( 10 * 1000 );
        time = System.nanoTime() - time;
        System.err.println( "time: " + ( time / 10000 ) / 100.0 + "ms" );
    }
}

Java 1.7.0_04 के साथ यह C संस्करण के समान ही तेजी से चलता है। क्लाइंट या सर्वर वीएम ज्यादा अंतर नहीं दिखाता है, सिवाय इसके कि जेआईटी प्रशिक्षण सर्वर वीएम को थोड़ा मदद करने के लिए लगता है (~ 3%) जबकि इसका क्लाइंट वीएम के साथ लगभग कोई प्रभाव नहीं है। जावा में आउटपुट सी की तुलना में धीमा प्रतीत होता है। यदि आउटपुट को दोनों संस्करणों में स्थिर काउंटर से बदल दिया जाता है, तो जावा संस्करण सी संस्करण की तुलना में थोड़ा तेज चलता है।

ये 100k रन के लिए मेरा समय हैं:

  • 319ms C / NIL के साथ संकलित / ऑक्स और आउटपुट के साथ:
  • 312ms C / Ox और स्थिर काउंटर के साथ संकलित किया गया
  • 324ms जावा क्लाइंट VM आउटपुट के साथ> NIL:
  • स्थैतिक काउंटर के साथ 299ms जावा क्लाइंट वीएम

और 1M रन (16386 परिणाम):

  • 24.95s C / Ox और स्थिर काउंटर के साथ संकलित किया गया
  • 25.08s जावा क्लाइंट वीएम स्टेटिक काउंटर के साथ
  • 24.86s जावा सर्वर वीएम स्टेटिक काउंटर के साथ

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

यह एक संकेत भी देता है कि स्काला क्यों तेज लगती है। यह जावा वीएम पर चलता है और इस प्रकार इसके प्रभावशाली प्रदर्शन से लाभ होता है।


1
प्राइम चेक फ़ंक्शन के लिए x >> 1 के बजाय sqrt (x) पर जाना तेज़ है।
ईव फ्रीमैन

4

Scala में List के बजाय Tuple2 का उपयोग करने का प्रयास करें, यह तेजी से जाना चाहिए। बस 'सूची' शब्द को हटा दें (x, y) एक Tuple2 है।

Tuple2 Int, Long और Double के लिए विशिष्ट है, इसका मतलब यह नहीं है कि उन कच्चे डेटाटिप्स को बॉक्स / अनबॉक्स करना होगा। Tuple2 स्रोत । सूची विशेष नहीं है सूची स्रोत


तब आप forallउस पर कॉल नहीं कर सकते । मैंने यह भी सोचा कि यह सबसे कुशल कोड नहीं हो सकता है (अधिक क्योंकि nकेवल एक दृश्य का उपयोग करने के बजाय बड़े के लिए एक बड़ा सख्त संग्रह बनाया जाता है ), लेकिन यह निश्चित रूप से छोटा + सुरुचिपूर्ण है, और मुझे आश्चर्य हुआ कि इसका उपयोग करने के बावजूद यह कितना अच्छा प्रदर्शन किया बहुत कार्यात्मक शैली।
0__

आप सही हैं, मुझे लगा कि 'फॉर ऑल' था। फिर भी सूची में एक बड़ा सुधार होना चाहिए और उन 2 कॉलों को करना बुरा नहीं होगा।
टॉमस लजारो

2
यह वास्तव में तेज़ है, इसके साथ def sexyPrimes(n: Int) = (11 to n).map(i => (i-6, i)).filter({ case (i, j) => isPrime(i) && isPrime(j) })यहाँ लगभग 60% तेज है, इसलिए C कोड को हरा देना चाहिए :)
0__

हम्म, मुझे केवल 4 या 5% की प्रदर्शन वृद्धि हुई है
लुइगी प्लिंज

1
मुझे collectकाफी धीमा लगता है। यदि आप पहले फ़िल्टर करें और फिर मैप करें तो तेज़। withFilterयह थोड़ा तेज़ है क्योंकि यह वास्तव में मध्यवर्ती संग्रह नहीं बनाता है। (11 to n) withFilter (i => isPrime(i - 6) && isPrime(i)) map (i => (i - 6, i))
लुइगी प्लिंज

4

यहाँ गो (golang.org) संस्करण के लिए कोड है:

package main

import (
    "fmt"
)


func main(){
    findprimes(10*1000)
}

func isprime(x int) bool {
    for i := 2; i < x; i++ {
        if x%i == 0 {
            return false
        }
    }
    return true
}

func findprimes(m int){
    for i := 11; i < m; i++ {
        if isprime(i) && isprime(i-6) {
            fmt.Printf("%d %d\n", i-6, i)
        }
    }
}

यह सी संस्करण के रूप में तेजी से भाग गया।

Asus u81a Intel Core 2 डुओ T6500 2.1GHz, 2MB L2 कैश, 800MHz FSB का उपयोग करना। 4 जीबी रैम

100k संस्करण: C: 2.723s Go: 2.743s

1000000 (100K के बजाय 1M) के साथ: C: 3m35.458s Go: 3m36.259s

लेकिन मुझे लगता है कि गो की मल्टीथ्रेडिंग क्षमताओं में निर्मित और नियमित सी संस्करण (बिना मल्टीथ्रेडिंग) वाले संस्करण की तुलना करना उचित होगा, सिर्फ इसलिए कि गो के साथ मल्टीथ्रेडिंग करना बहुत आसान है।

अद्यतन: मैंने गोरीटाइन को गो में उपयोग करके एक समानांतर संस्करण किया:

package main

import (
  "fmt"
  "runtime"
)

func main(){
    runtime.GOMAXPROCS(4)
    printer := make(chan string)
    printer2 := make(chan string)
    printer3 := make(chan string)
    printer4 := make(chan string)
    finished := make(chan int)

    var buffer, buffer2, buffer3 string

    running := 4
    go findprimes(11, 30000, printer, finished)
    go findprimes(30001, 60000, printer2, finished)
    go findprimes(60001, 85000, printer3, finished)
    go findprimes(85001, 100000, printer4, finished)

    for {
      select {
        case i := <-printer:
          // batch of sexy primes received from printer channel 1, print them
          fmt.Printf(i)
        case i := <-printer2:
          // sexy prime list received from channel, store it
          buffer = i
        case i := <-printer3:
          // sexy prime list received from channel, store it
          buffer2 = i
        case i := <-printer4:
          // sexy prime list received from channel, store it
          buffer3 = i
        case <-finished:
          running--
          if running == 0 {
              // all goroutines ended
              // dump buffer to stdout
              fmt.Printf(buffer)
              fmt.Printf(buffer2)
              fmt.Printf(buffer3)
              return
          }
      }
    }
}

func isprime(x int) bool {
    for i := 2; i < x; i++ {
        if x%i == 0 {
            return false
        }
    }
    return true
}

func findprimes(from int, to int, printer chan string, finished chan int){
    str := ""
    for i := from; i <= to; i++ {
        if isprime(i) && isprime(i-6) {
            str = str + fmt.Sprintf("%d %d\n", i-6, i)
      }
    }
    printer <- str
    //fmt.Printf("Finished %d to %d\n", from, to)
    finished <- 1
}

समानांतर संस्करण औसतन 2.743 सेकंड में उपयोग किया जाता है, ठीक उसी समय जिसका नियमित संस्करण उपयोग किया जाता है।

1.706 सेकंड में पूरा किया गया समानांतर संस्करण। इसमें 1.5 एमबी से कम रैम का इस्तेमाल किया गया था।

एक अजीब बात: मेरे दोहरे कोर कुबंटू 64 बिट दोनों कोर में कभी नहीं बढ़े। ऐसा लग रहा था कि गो केवल एक कोर का उपयोग कर रहा था। के लिए एक कॉल के साथ फिक्स्डruntime.GOMAXPROCS(4)

अपडेट: मैंने 1M नंबरों तक पैरेललाइज़्ड वर्जन चलाया। My CPU कोर में से एक हर समय 100% पर था, जबकि दूसरे का उपयोग बिल्कुल भी नहीं किया गया था (विषम)। सी और रेगुलर गो संस्करणों की तुलना में पूरे एक मिनट अधिक समय लगा। :(

1000000 (100K के बजाय 1M) के साथ:

C: 3m35.458s Go: 3m36.259s Go using goroutines:3m27.137s2m16.125s

100k संस्करण:

C: 2.723s Go: 2.743s Go using goroutines: 1.706s


आपने कितने कोर का उपयोग किया है?
ओम-नॉम-नॉम-जुले

2
मेरे पास Asus u81a Intel Core 2 Duo T6500 2.1GHz, 2MB L2 कैश, 800MHz FSB है। 4GB RAM
सेबेस्टियन ग्रिग्नोली

क्या आपने वास्तव में सक्षम किए गए अनुकूलन वाले सी संस्करण को संकलित किया है? डिफ़ॉल्ट गो संकलक इनलाइन नहीं करता है, और आमतौर पर इस तरह की तुलना में अनुकूलित सी के खिलाफ एक बड़े पैमाने पर प्रदर्शन हिट होगा। -O3या बेहतर जोड़ें ।
मैट जॉइनर

मैंने अभी किया, पहले नहीं, और 100K संस्करण के साथ या बिना -O3 के समान समय लिया
सेबस्टियन ग्रिग्नोली

1M संस्करण के लिए एक ही बात। हो सकता है कि यह विशेष ऑपरेशन (हम एक बहुत छोटे उपसमूह का परीक्षण कर रहे हैं) डिफ़ॉल्ट रूप से अच्छी तरह से अनुकूलित हैं।
सेबेस्टियन ग्रिग्नोली

4

बस इसके मज़े के लिए, यहाँ एक समानांतर रूबी संस्करण है।

require 'benchmark'

num = ARGV[0].to_i

def is_prime?(n)
  (2...n).all?{|m| n%m != 0 }
end

def sexy_primes_default(x)
    (9..x).map do |i|
        [i-6, i]
    end.select do |j|
        j.all?{|j| is_prime? j}
    end
end

def sexy_primes_threads(x)
    partition = (9..x).map do |i|
        [i-6, i]
    end.group_by do |x|
        x[0].to_s[-1]
    end
    threads = Array.new
    partition.each_key do |k|
       threads << Thread.new do
            partition[k].select do |j|
                j.all?{|j| is_prime? j}
            end
        end
    end
    threads.each {|t| t.join}
    threads.map{|t| t.value}.reject{|x| x.empty?}
end

puts "Running up to num #{num}"

Benchmark.bm(10) do |x|
    x.report("default") {a = sexy_primes_default(num)}
    x.report("threads") {a = sexy_primes_threads(num)}
end

मेरे 1.8GHz कोर i5 मैकबुक एयर पर, प्रदर्शन परिणाम हैं:

# Ruby 1.9.3
$ ./sexyprimes.rb 100000
Running up to num 100000
                 user     system      total        real
default     68.840000   0.060000  68.900000 ( 68.922703)
threads     71.730000   0.090000  71.820000 ( 71.847346)

# JRuby 1.6.7.2 on JVM 1.7.0_05
$ jruby --1.9 --server sexyprimes.rb 100000
Running up to num 100000
                user     system      total        real
default    56.709000   0.000000  56.709000 ( 56.708000)
threads    36.396000   0.000000  36.396000 ( 36.396000)

# JRuby 1.7.0.preview1 on JVM 1.7.0_05
$ jruby --server sexyprimes.rb 100000
Running up to num 100000
             user     system      total        real
default     52.640000   0.270000  52.910000 ( 51.393000)
threads    105.700000   0.290000 105.990000 ( 30.298000)

ऐसा लगता है कि जेवीएम की जेआईटी रूबी को डिफ़ॉल्ट मामले में एक अच्छा प्रदर्शन को बढ़ावा दे रही है, जबकि सच्चा मल्टीथ्रेडिंग जेआरयूबी थ्रेडेड मामले में 50% तेजी से प्रदर्शन करने में मदद करता है। क्या अधिक दिलचस्प है कि JRuby 1.7 स्वस्थ 17% द्वारा JRuby 1.6 स्कोर में सुधार करता है!


3

X4u के उत्तर के आधार पर , मैंने पुनरावर्तन का उपयोग करते हुए एक स्कैला संस्करण लिखा, और मैंने उस पर केवल प्राइम चेक फ़ंक्शन के लिए x / 2 के बजाय sqrt पर जाकर सुधार किया। मुझे 100k के लिए ~ 250ms, और 1M के लिए ~ 600ms मिलते हैं। मैं आगे गया और ~ 6s में 10M गया।

import scala.annotation.tailrec

var count = 0;
def print(i:Int) = {
  println((i - 6) + " " + i)
  count += 1
}

@tailrec def isPrime(n:Int, i:Int = 3):Boolean = {
  if(n % i == 0) return false;
  else if(i * i > n) return true;
  else isPrime(n = n, i = i + 2)
}      

@tailrec def findPrimes(max:Int, bitMask:Int = 3, i:Int = 11):Unit = {
  if (isPrime(i)) {
    if((bitMask & 1) != 0) print(i)
    if(i + 2 < max) findPrimes(max = max, bitMask = (bitMask | (1 << 3)) >> 1, i = i + 2)
  } else if(i + 2 < max) {
    findPrimes(max = max, bitMask = bitMask >> 1, i = i + 2)
  }
}

val a = System.currentTimeMillis()
findPrimes(max=10000000)
println(count)
val b = System.currentTimeMillis()
println((b - a).toString + " mils")

मैंने भी वापस जाकर एक कॉफीस्क्रिप्ट (V8 जावास्क्रिप्ट) संस्करण लिखा, जो ~ काउंटर के लिए (आई / ओ को नजरअंदाज करके) 100M के लिए ~ 15ms, 1M के लिए 250ms और 10M के लिए 6s का हो जाता है। अगर मैं आउटपुट को चालू करता हूं तो यह 100k के लिए ~ 150ms, 1M के लिए 1s और 10M के लिए 12s लेता है। यहाँ पूंछ पुनरावृत्ति का उपयोग नहीं किया जा सकता है, दुर्भाग्य से, इसलिए मुझे इसे वापस छोरों में बदलना पड़ा।

count = 0;
print = (i) ->
  console.log("#{i - 6} #{i}")
  count += 1
  return

isPrime = (n) ->
  i = 3
  while i * i < n
    if n % i == 0
      return false
    i += 2
  return true

findPrimes = (max) ->
  bitMask = 3
  for i in [11..max] by 2
    prime = isPrime(i)
    if prime
      if (bitMask & 1) != 0
        print(i)
      bitMask |= (1 << 3)
    bitMask >>= 1
  return

a = new Date()
findPrimes(1000000)
console.log(count)
b = new Date()
console.log((b - a) + " ms")

2

आपके प्रश्न # 1 का उत्तर यह है कि हाँ, JVM अविश्वसनीय रूप से तेज़ है और हाँ स्थैतिक टाइपिंग में मदद करता है।

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

जावा की गति के कारण हैं:

JVM आपके कोड का विश्लेषण कर सकता है जबकि यह चलता है और इसे हाथ से ऑप्टिमाइज़ करता है - उदाहरण के लिए, यदि आपके पास एक ऐसा तरीका है जिसे एक सच्चे कार्य के लिए संकलित समय पर सांख्यिकीय रूप से विश्लेषण किया जा सकता है और JVM ने देखा कि आप अक्सर इसे उसी के साथ बुला रहे थे। पैरामीटर, यह वास्तव में कॉल को पूरी तरह से खत्म कर देता है और अंतिम कॉल से परिणामों को इंजेक्ट करता है (मुझे यकीन नहीं है कि जावा वास्तव में ऐसा करता है, लेकिन यह इस तरह का बहुत सारा सामान करता है)।

स्टैटिक टाइपिंग के कारण, JVM संकलन समय पर आपके कोड के बारे में बहुत कुछ जान सकता है, इससे यह थोड़ा बहुत पूर्व-अनुकूलन कर देता है। यह संकलक को प्रत्येक वर्ग को व्यक्तिगत रूप से यह जानने की अनुमति देता है कि कोई अन्य वर्ग इसका उपयोग करने की योजना कैसे बना रहा है। इसके अलावा जावा में मेमोरी स्थान के लिए मनमाने ढंग से पॉइंटर्स नहीं हैं, यह जानता है कि मेमोरी में कौन से मूल्य हैं और जिन्हें बदला नहीं जा सकता है और वे तदनुसार अनुकूलित कर सकते हैं।

हीप आवंटन MUCH C से अधिक कुशल है, जावा का हीप आवंटन C की गति में स्टैक आवंटन की तरह अधिक है - फिर भी अधिक बहुमुखी। यहाँ उपयोग किए गए विभिन्न एल्ग्रिथिथियों में बहुत समय बीत गया है, यह एक कला है - उदाहरण के लिए, एक छोटी उम्र (जैसे सी के ढेर वाले चर) के साथ सभी वस्तुओं को एक "ज्ञात" मुक्त स्थान (एक मुक्त स्थान की खोज नहीं) के लिए आवंटित किया जाता है। पर्याप्त स्थान के साथ) और सभी को एक एकल चरण (एक स्टैक पॉप की तरह) में एक साथ मुक्त किया गया है।

JVM आपके CPU आर्किटेक्चर के बारे में जानकारी प्राप्त कर सकता है और विशेष रूप से दिए गए CPU के लिए मशीन कोड जनरेट कर सकता है।

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

वैसे, JVM को लोड करने के लिए java की गति के लिए अधिकांश बुरे प्रतिनिधि लंबे स्टार्टअप समय से आते हैं (किसी दिन JVM को OS में बनाया जाएगा और यह चला जाएगा!) और यह तथ्य कि कई डेवलपर्स लेखन के लिए वास्तव में खराब हैं। GUI कोड (विशेष रूप से पिरोया गया) जिसके कारण जावा GUI अक्सर अनुत्तरदायी और गड़बड़ हो जाता है। जावा और वीबी जैसी भाषाओं का उपयोग करने के लिए सरल उनके दोष इस तथ्य से बढ़े हैं कि औसत प्रोग्रामर की क्षमताएं अधिक जटिल भाषाओं की तुलना में कम हो जाती हैं।


यह कहना कि जेवीएम का ढेर आवंटन, गैर-संवेदी है, की तुलना में कहीं अधिक कुशल है, जिसे JVM C ++ में लिखा गया है।
डैनियल सी। सोबरल

5
@ डैनियल सी.सोबरल भाषा उतनी महत्वपूर्ण नहीं है जितना कि इम्प्लिमेंटेशन - जावा का "हीप" कार्यान्वयन कोड, C की तरह कुछ भी नहीं है। जावा की एक बदली मल्टी-स्टेज प्रणाली है, जो कि आज के अत्याधुनिक तकनीकों सहित अनुसंधान में कई वर्षों के प्रयासों के साथ विभिन्न लक्ष्यों के लिए अत्यधिक अनुकूल है, सी एक ढेर का उपयोग करता है - एक साधारण डेटा संरचना विकसित युगों पहले। जावा की प्रणाली सी के लिए लागू करने के लिए असंभव है, सी दिया गया है कि सी पॉइंटर्स की अनुमति देता है, इसलिए यह बिना भाषा परिवर्तन के मनमाने ढंग से आवंटित मेमोरी चंक्स के "सुरक्षित" चालों की गारंटी नहीं दे सकता (इसे अब सी नहीं प्रदान करता है)
बिल के

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

आपने "सेफ" के मेरे अर्थ को गलत समझा होगा - जावा किसी भी समय मेमोरी के एंटी आर्बिटिक ब्लॉक को स्थानांतरित करने में सक्षम है क्योंकि यह जानता है कि सी, मेमोरी एलोकेशन को ऑप्टोमाइज़ करने में असमर्थ है क्योंकि इसमें एक पॉइंटर हो सकता है जो इसे संदर्भित कर सकता है। इसके अलावा एसी ढेर आमतौर पर एक ढेर के रूप में लागू किया जाता है जो एक डेटा संरचना है। C ++ ढेर को C जैसी ढेर संरचनाओं के साथ कार्यान्वित किया जाता था (इसलिए नाम, "हीप") मैंने कुछ वर्षों तक C ++ में जाँच नहीं की है, इसलिए यह अब सच नहीं हो सकता है, लेकिन यह अभी भी सीमित नहीं है उपयोगकर्ता की आवंटित मेमोरी के छोटे हिस्से को फिर से व्यवस्थित करें।
बिल के।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.