Pour comparer les performances de Spark lors de l'utilisation de Python et Scala, j'ai créé le même travail dans les deux langues et comparé le runtime. Je m'attendais à ce que les deux travaux prennent à peu près la même quantité de temps, mais le travail Python a pris seulement 27min
, tandis que le travail Scala a pris 37min
(presque 40% de plus!). J'ai également implémenté le même travail en Java et cela a 37minutes
également pris . Comment est-il possible que Python soit tellement plus rapide?
Exemple minimal vérifiable:
Travail Python:
# 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)
Emploi Scala:
// 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")
Rien qu'en regardant le code, ils semblent identiques. J'ai regardé les DAG et ils n'ont fourni aucun aperçu (ou du moins je n'ai pas le savoir-faire pour trouver une explication basée sur eux).
J'apprécierais vraiment tous les conseils.
la source
Réponses:
Votre hypothèse de base, que Scala ou Java devrait être plus rapide pour cette tâche spécifique, est tout simplement incorrecte. Vous pouvez facilement le vérifier avec un minimum d'applications locales. Scala one:
Python un
Résultats (300 répétitions chacun, Python 3.7.6, Scala 2.11.12), à
Posts.xml
partir du vidage de données hermeneutics.stackexchange.com avec un mélange de modèles correspondants et non correspondants:Comme vous le voyez, Python est non seulement systématiquement plus rapide, mais également plus cohérent (propagation plus faible).
Le message à retenir est - ne croyez pas FUD non corroboré - les langues peuvent être plus rapides ou plus lentes sur des tâches spécifiques ou avec des environnements spécifiques (par exemple ici Scala peut être touché par le démarrage de la JVM et / ou GC et / ou JIT), mais si vous le prétendez comme "XYZ est X4 plus rapide" ou "XYZ est lent par rapport à ZYX (..) Environ 10 fois plus lent", cela signifie généralement que quelqu'un a écrit un très mauvais code pour tester les choses.
Modifier :
Pour répondre à certaines préoccupations soulevées dans les commentaires:
local_connect_and_auth
, et ce n'est rien d'autre que le fichier associé au socket ). Encore une fois, aussi bon marché que possible en ce qui concerne la communication entre les processus.Modifier 2 :
Puisque jasper-m était préoccupé par le coût de démarrage ici, on peut facilement prouver que Python a encore un avantage significatif sur Scala même si la taille d'entrée est considérablement augmentée.
Voici les résultats pour 2003360 lignes / 5.6G (la même entrée, juste dupliquée plusieurs fois, 30 répétitions), ce qui dépasse tout ce que vous pouvez attendre dans une seule tâche Spark.
Veuillez noter les intervalles de confiance qui ne se chevauchent pas.
Modifier 3 :
Pour répondre à un autre commentaire de Jasper-M:
C'est tout simplement incorrect dans ce cas particulier:
DataFrame
) implémente nativement des fonctionnalités natives en Python, avec des exceptions d'entrée, de sortie et de communication entre les nœuds.la source
Le travail Scala prend plus de temps car il a une mauvaise configuration et, par conséquent, les travaux Python et Scala ont été fournis avec des ressources inégales.
Il y a deux erreurs dans le code:
sc.hadoopConfiguration
est un mauvais endroit pour définir une configuration Spark. Il doit être défini dans l'config
instance à laquelle vous passeznew SparkContext(config)
.[AJOUTÉ] Compte tenu de ce qui précède, je proposerais de changer le code du travail Scala en
et le tester à nouveau. Je parie que la version Scala va être X fois plus rapide maintenant.
la source