Spark:为什么Python在我的用例中显著优于Scala?
为了比较Spark在使用Python和Scala时的性能,我用两种语言创建了相同的作业,并比较了运行时。我预计这两个作业所用的时间大致相同,但Python作业只花了Spark:为什么Python在我的用例中显著优于Scala?,python,scala,apache-spark,pyspark,Python,Scala,Apache Spark,Pyspark,为了比较Spark在使用Python和Scala时的性能,我用两种语言创建了相同的作业,并比较了运行时。我预计这两个作业所用的时间大致相同,但Python作业只花了27分钟,而Scala作业则花了37分钟(几乎长了40%)。我也在Java中实现了同样的工作,而且花了37分钟。Python的速度怎么可能快得多 最小可验证示例: Python作业: #配置 conf=pyspark.SparkConf() conf.set(“spark.hadoop.fs.s3a.aws.credentials.p
27分钟,而Scala作业则花了37分钟(几乎长了40%)。我也在Java中实现了同样的工作,而且花了37分钟。Python的速度怎么可能快得多
最小可验证示例:
Python作业:
#配置
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个文件
input_files=“s3a://commoncrawl/crawl data/CC-MAIN-2019-35/segments/156602731205.20/warc/CC-MAIN-20190817203056-20190817225056-00[0-5]*”
输入文件2=“s3a://commoncrawl/crawl data/CC-MAIN-2019-35/segments/156027312128.3/warc/CC-MAIN-20190817102624-20190817124624-00[0-3]*”
#计算某个字符串的发生次数
logData=sc.textFile(输入文件)
logData2=sc.textFile(输入文件2)
a=logData.filter(lambda值:value.startswith('WARC-Type:response')).count()
b=logData2.filter(lambda值:value.startswith('WARC-Type:response')).count()
印刷品(a、b)
Scala作业:
//配置
config.set(“spark.executor.instances”,“4”)
config.set(“spark.executor.cores”,“8”)
val sc=新的SparkContext(配置)
sc.setLogLevel(“警告”)
sc.hadoopConfiguration.set(“fs.s3a.aws.credentials.provider”、“org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider”)
//分两批从公共数据集中获取960个文件
val input_files=“s3a://commoncrawl/crawl data/CC-MAIN-2019-35/segments/156602731205.20/warc/CC-MAIN-20190817203056-20190817225056-00[0-5]*”
val input_files2=“s3a://commoncrawl/crawl data/CC-MAIN-2019-35/segments/156027312128.3/warc/CC-MAIN-20190817102624-20190817124624-00[0-3]*”
//计算某个字符串的发生次数
val logData1=sc.textFile(输入文件)
val logData2=sc.textFile(输入文件2)
val num1=logData1.filter(line=>line.startsWith(“WARC类型:响应”)).count()
val num2=logData2.filter(line=>line.startsWith(“WARC类型:响应”)).count()
println(s“带a:$num1的行,带b:$num2的行”)
只要看一下代码,它们似乎是相同的。我看了一眼DAG,他们没有提供任何见解(或者至少我缺乏根据DAG做出解释的知识)
如果有人给我指点,我将不胜感激 Scala作业需要更长的时间,因为它有一个错误的配置,因此,Python和Scala作业提供了不同的资源
代码中有两个错误:
val sc=new SparkContext(config)//第1行
sc.setLogLevel(“警告”)
sc.hadoopConfiguration.set(“fs.s3a.aws.credentials.provider”、“org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider”)
sc.hadoopConfiguration.set(“spark.executor.instances”,“4”)//第4行
sc.hadoopConfiguration.set(“spark.executor.cores”,“8”)//第5行
第1行。执行该行后,Spark作业的资源配置已经建立并固定。从这一点开始,没有办法调整任何事情。无论是执行器的数量还是每个执行器的内核数量
第4-5行sc.hadoopConfiguration
是设置任何Spark配置的错误位置。应该在传递给newsparkcontext(config)
的config
实例中设置它
[补充]
考虑到上述情况,我建议将Scala作业的代码更改为
config.set(“spark.executor.instances”,“4”)
config.set(“spark.executor.cores”,“8”)
val sc=new SparkContext(config)//第1行
sc.setLogLevel(“警告”)
sc.hadoopConfiguration.set(“fs.s3a.aws.credentials.provider”、“org.apache.hadoop.fs.s3a.AnonymousAWSCredentialsProvider”)
然后再次测试它。我打赌Scala版本现在会快X倍。您的基本假设,即Scala或Java对于这个特定任务应该更快,这是不正确的。您可以使用最少的本地应用程序轻松验证它。Scala one:
导入scala.io.Source
导入java.time.{Duration,Instant}
对象应用程序{
def main(参数:数组[字符串]){
val数组(文件名,字符串)=args
val start=Instant.now()
来源
.fromFile(文件名)
.getLines
.filter(line=>line.startsWith(字符串))
.长度
val stop=Instant.now()
val duration=持续时间。介于(开始、停止)之间。toMillis
println(s“${start},${stop},${duration}”)
}
}
巨蟒一号
导入日期时间
导入系统
如果名称=“\uuuuu main\uuuuuuuu”:
_,文件名,字符串=sys.argv
start=datetime.datetime.now()
打开(文件名)为fr时:
#不是惯用的或最有效的,但这就是
#Pypark将使用
总和(1表示过滤器中的uu(lambda行:line.startswith(string),fr))
end=datetime.datetime.now()
持续时间=整轮((结束-开始)。总秒数()*1000)
打印(f“{start},{end},{duration}”)
结果(每个重复300次,Python 3.7.6,Scala 2.11.12),在Posts.xml
上,混合使用匹配和非匹配模式:
- Python 273.50(258.84288.16)
- 斯卡拉634.13(533.81734.45)
正如您所看到的,Python不仅系统性地更快,而且更一致(传播速度更低)
带走的信息是‒不要相信未经证实的‒语言在特定任务或特定环境中可以更快或更慢(例如,这里Scala可能会受到JVM启动和/或GC和/或JIT的影响),但如果您声称“XYZ比ZYX快X4”或“XYZ比ZYX慢约10倍”这通常意味着有人写了