Para comparar o desempenho do Spark ao usar Python e Scala, criei o mesmo trabalho nos dois idiomas e comparei o tempo de execução. Eu esperava que os dois trabalhos levassem aproximadamente a mesma quantidade de tempo, mas o trabalho em Python levou apenas 27min
, enquanto o trabalho em Scala demorou 37min
(quase 40% mais!). Também implementei o mesmo trabalho em Java e também demorou 37minutes
. Como é possível que o Python seja muito mais rápido?
Exemplo mínimo verificável:
Trabalho em 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)
Trabalho 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")
Apenas olhando o código, eles parecem idênticos. Procurei nos DAGs e eles não forneceram nenhuma informação (ou pelo menos não tenho o conhecimento necessário para apresentar uma explicação baseada neles).
Eu realmente aprecio qualquer indicação.
fonte
Respostas:
Sua suposição básica, de que Scala ou Java deve ser mais rápido para esta tarefa específica, está incorreta. Você pode verificá-lo facilmente com aplicativos locais mínimos. Scala one:
Python one
Resultados (300 repetições cada, Python 3.7.6, Scala 2.11.12), a
Posts.xml
partir do dump de dados hermeneutics.stackexchange.com com mistura de padrões correspondentes e não correspondentes:Como você vê, o Python não é apenas sistematicamente mais rápido, mas também é mais consistente (menor propagação).
A mensagem de retirada é - não acredite no FUD sem fundamento - os idiomas podem ser mais rápidos ou mais lentos em tarefas específicas ou em ambientes específicos (por exemplo, aqui o Scala pode ser atingido pela inicialização da JVM e / ou GC e / ou JIT), mas se você alega como "XYZ é X4 mais rápido" ou "XYZ é lento em comparação com ZYX (..) Aproximadamente, 10 vezes mais lento" geralmente significa que alguém escreveu um código muito ruim para testar as coisas.
Editar :
Para resolver algumas preocupações levantadas nos comentários:
local_connect_and_auth
, e nada mais é que o arquivo associado ao soquete ). Novamente, o mais barato possível quando se trata de comunicação entre processos.Edição 2 :
Como o jasper-m estava preocupado com o custo de inicialização aqui, pode-se facilmente provar que o Python ainda possui uma vantagem significativa sobre o Scala, mesmo que o tamanho da entrada seja significativamente aumentado.
Aqui estão os resultados para 2003360 linhas / 5,6G (a mesma entrada, apenas duplicada várias vezes, 30 repetições), o que excede o que você pode esperar em uma única tarefa do Spark.
Observe intervalos de confiança não sobrepostos.
Edição 3 :
Para abordar outro comentário de Jasper-M:
Isso é simplesmente incorreto neste caso específico:
DataFrame
) implementa uma grande quantidade de funcionalidades nativamente no Python, com entrada, saída e comunicação entre nós de exceção.fonte
O trabalho do Scala leva mais tempo porque possui uma configuração incorreta e, portanto, os trabalhos do Python e do Scala foram fornecidos com recursos desiguais.
Existem dois erros no código:
sc.hadoopConfiguration
é um lugar errado para definir qualquer configuração do Spark. Deve ser definido naconfig
instância para a qual você passanew SparkContext(config)
.[ADICIONADO] Tendo em mente o acima exposto, proponho alterar o código do trabalho do Scala para
e teste novamente. Aposto que a versão Scala será X vezes mais rápida agora.
fonte