Um die Leistung von Spark bei Verwendung von Python und Scala zu vergleichen, habe ich denselben Job in beiden Sprachen erstellt und die Laufzeit verglichen. Ich hatte erwartet, dass beide Jobs ungefähr gleich lange dauern würden, aber der Python-Job dauerte nur 27min
, während der Scala-Job dauerte 37min
(fast 40% länger!). Ich habe den gleichen Job auch in Java implementiert und es hat auch 37minutes
gedauert. Wie ist das möglich, dass Python so viel schneller ist?
Minimales überprüfbares Beispiel:
Python-Job:
# Configuration
conf = pyspark.SparkConf()
conf.set("spark.hadoop.fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider")
conf.set("spark.executor.instances", "4")
conf.set("spark.executor.cores", "8")
sc = pyspark.SparkContext(conf=conf)
# 960 Files from a public dataset in 2 batches
input_files = "s3a://commoncrawl/crawl-data/CC-MAIN-2019-35/segments/1566027312025.20/warc/CC-MAIN-20190817203056-20190817225056-00[0-5]*"
input_files2 = "s3a://commoncrawl/crawl-data/CC-MAIN-2019-35/segments/1566027312128.3/warc/CC-MAIN-20190817102624-20190817124624-00[0-3]*"
# Count occurances of a certain string
logData = sc.textFile(input_files)
logData2 = sc.textFile(input_files2)
a = logData.filter(lambda value: value.startswith('WARC-Type: response')).count()
b = logData2.filter(lambda value: value.startswith('WARC-Type: response')).count()
print(a, b)
Scala Job:
// Configuration
config.set("spark.executor.instances", "4")
config.set("spark.executor.cores", "8")
val sc = new SparkContext(config)
sc.setLogLevel("WARN")
sc.hadoopConfiguration.set("fs.s3a.aws.credentials.provider", "org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider")
// 960 Files from a public dataset in 2 batches
val input_files = "s3a://commoncrawl/crawl-data/CC-MAIN-2019-35/segments/1566027312025.20/warc/CC-MAIN-20190817203056-20190817225056-00[0-5]*"
val input_files2 = "s3a://commoncrawl/crawl-data/CC-MAIN-2019-35/segments/1566027312128.3/warc/CC-MAIN-20190817102624-20190817124624-00[0-3]*"
// Count occurances of a certain string
val logData1 = sc.textFile(input_files)
val logData2 = sc.textFile(input_files2)
val num1 = logData1.filter(line => line.startsWith("WARC-Type: response")).count()
val num2 = logData2.filter(line => line.startsWith("WARC-Type: response")).count()
println(s"Lines with a: $num1, Lines with b: $num2")
Wenn man sich nur den Code ansieht, scheinen sie identisch zu sein. Ich habe mir die DAGs angesehen und sie haben keine Erkenntnisse geliefert (oder zumindest fehlt mir das Know-how, um eine darauf basierende Erklärung zu finden).
Ich würde mich über Hinweise sehr freuen.
quelle
Antworten:
Ihre Grundannahme, dass Scala oder Java für diese spezielle Aufgabe schneller sein sollten, ist einfach falsch. Sie können dies problemlos mit minimalen lokalen Anwendungen überprüfen. Scala eins:
Python eins
Ergebnisse (jeweils 300 Wiederholungen, Python 3.7.6, Scala 2.11.12)
Posts.xml
aus dem Datendump von hermeneutics.stackexchange.com mit einer Mischung aus übereinstimmenden und nicht übereinstimmenden Mustern:Wie Sie sehen, ist Python nicht nur systematisch schneller, sondern auch konsistenter (geringere Verbreitung).
Die Nachricht zum Mitnehmen lautet - glauben Sie nicht, dass unbegründete FUD - Sprachen bei bestimmten Aufgaben oder in bestimmten Umgebungen schneller oder langsamer sein können (hier kann Scala beispielsweise vom JVM-Start und / oder GC und / oder JIT getroffen werden), aber wenn Sie dies behaupten wie "XYZ ist X4 schneller" oder "XYZ ist langsam im Vergleich zu ZYX (..) Ungefähr 10x langsamer" bedeutet dies normalerweise, dass jemand wirklich schlechten Code geschrieben hat, um Dinge zu testen.
Bearbeiten :
Um einige in den Kommentaren angesprochene Bedenken auszuräumen:
local_connect_and_auth
, und es ist nichts anderes als Socket - Datei ). Wieder so billig wie es nur geht, wenn es um die Kommunikation zwischen Prozessen geht.Bearbeiten 2 :
Da Jasper-m hier über die Startkosten besorgt war, kann man leicht beweisen, dass Python gegenüber Scala immer noch einen erheblichen Vorteil hat, selbst wenn die Eingabegröße erheblich erhöht wird.
Hier sind die Ergebnisse für 2003360 Zeilen / 5.6G (dieselbe Eingabe, nur mehrfach dupliziert, 30 Wiederholungen), die alles übertreffen, was Sie von einer einzelnen Spark-Aufgabe erwarten können.
Bitte beachten Sie nicht überlappende Konfidenzintervalle.
Edit 3 :
Um einen weiteren Kommentar von Jasper-M anzusprechen :
Das ist in diesem speziellen Fall einfach falsch:
DataFrame
) eine Vielzahl von Funktionen nativ in Python, mit Ausnahme der Eingabe, Ausgabe und Kommunikation zwischen Knoten.quelle
Der Scala-Job dauert länger, da er falsch konfiguriert ist und daher die Python- und Scala-Jobs mit ungleichen Ressourcen ausgestattet wurden.
Der Code enthält zwei Fehler:
sc.hadoopConfiguration
ist ein falscher Ort, um eine Spark-Konfiguration festzulegen. Es sollte in derconfig
Instanz festgelegt werden, an die Sie übergebennew SparkContext(config)
.[HINZUGEFÜGT] Vor diesem Hintergrund würde ich vorschlagen, den Code des Scala-Jobs in zu ändern
und testen Sie es erneut. Ich wette, die Scala-Version wird jetzt X-mal schneller sein.
quelle