Aby porównać wydajność Spark przy użyciu Pythona i Scali, stworzyłem to samo zadanie w obu językach i porównałem środowisko wykonawcze. Spodziewałem się, że obie prace zajmą mniej więcej tyle samo czasu, ale praca w Pythonie trwała tylko 27min
, podczas gdy praca w Scali trwała 37min
(prawie 40% dłużej!). Zaimplementowałem również tę samą pracę w Javie i to 37minutes
też zajęło . Jak to możliwe, że Python jest o wiele szybszy?
Minimalny możliwy do zweryfikowania przykład:
Zadanie 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)
Praca 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")
Po prostu patrząc na kod wydają się identyczne. Spojrzałem na DAG i nie dostarczyli oni żadnych spostrzeżeń (a przynajmniej brakuje mi know-how, aby znaleźć na ich podstawie wyjaśnienie).
Byłbym naprawdę wdzięczny za wszelkie wskazówki.
python
scala
apache-spark
pyspark
maestromusica
źródło
źródło
Odpowiedzi:
Twoje podstawowe założenie, że Scala lub Java powinny być szybsze do tego konkretnego zadania, jest po prostu błędne. Możesz to łatwo zweryfikować za pomocą minimalnych aplikacji lokalnych. Scala One:
Python pierwszy
Wyniki (300 powtórzeń każda, Python 3.7.6, Scala 02.11.12) w sprawie
Posts.xml
z hermeneutics.stackexchange.com dane zrzucić z mieszanką i dopasowywania wzorców non pasujące:Jak widzisz, Python jest nie tylko systematycznie szybszy, ale także bardziej spójny (mniejszy spread).
Komunikat „zabierz” to - nie wierz w bezpodstawny FUD - języki mogą być szybsze lub wolniejsze w określonych zadaniach lub w określonych środowiskach (na przykład tutaj Scala może zostać uderzona przez uruchomienie JVM i / lub GC i / lub JIT), ale jeśli twierdzisz, że jak „XYZ jest X4 szybszy” lub „XYZ jest wolny w porównaniu do ZYX (..) Około, 10 razy wolniejszy” zwykle oznacza to, że ktoś napisał naprawdę zły kod do testowania.
Edytuj :
Aby zaradzić niektórym obawom wyrażonym w komentarzach:
local_connect_and_auth
i jest niczym innym jak plikiem powiązanym z gniazdem ). Ponownie, tak tanie, jak to możliwe, jeśli chodzi o komunikację między procesami.Edycja 2 :
Ponieważ jasper-m był zaniepokojony kosztem uruchomienia tutaj, łatwo można udowodnić, że Python nadal ma znaczącą przewagę nad Scalą, nawet jeśli rozmiar wejściowy zostanie znacznie zwiększony.
Oto wyniki dla 2003360 linii / 5.6G (to samo wejście, po prostu zduplikowane wiele razy, 30 powtórzeń), który to sposób przekracza wszystko, czego można oczekiwać w jednym zadaniu Spark.
Uwaga: nie nakładające się przedziały ufności.
Edycja 3 :
Aby odpowiedzieć na inny komentarz Jasper-M:
Jest to po prostu niepoprawne w tym konkretnym przypadku:
DataFrame
) implementuje ogromną funkcjonalność natywnie w Pythonie, z wyjątkami wejścia, wyjścia i komunikacji między węzłami.źródło
Zadanie Scala trwa dłużej, ponieważ ma błędną konfigurację, dlatego zadania Python i Scala zostały wyposażone w nierówne zasoby.
W kodzie są dwa błędy:
sc.hadoopConfiguration
jest złym miejscem do ustawienia dowolnej konfiguracji Spark. Powinien być ustawiony wconfig
instancji, którą przekazujesznew SparkContext(config)
.[DODANO] Mając powyższe na uwadze, proponuję zmienić kod zadania Scala na
i ponownie go przetestuj. Założę się, że wersja Scali będzie teraz X razy szybsza.
źródło