scala程序比相应的python脚本慢得多

Isr*_*man 3 scala

我编写了一个简短的Scala程序来读取一个大文件,处理它并将结果存储在另一个文件中.该文件包含大约60000行数字,我需要从每个第三行提取第一个数字.最后我将这些数字保存到另一个文件中.虽然数字,但我一直把它们视为字符串.

这是Scala代码:

import scala.io.Source
import java.io.BufferedWriter
import java.io.FileWriter

object Analyze {
  def main(args: Array[String]) {
      val fname = "input.txt"

      val counters = Source.fromFile(fname).mkString.split("\\n").grouped(3)
        .map(_(2).split("\\s+")(0))

      val f = new BufferedWriter(new FileWriter("output1.txt"))
      f.write(counters.reduceLeft(_ + "\n" + _))
      f.close()
  }
}
Run Code Online (Sandbox Code Playgroud)

我非常喜欢Scala强大的一个内衬的能力.上面代码中的单行读取文件中的整个文本,将其拆分为行,将行分组为3行组,然后从每个组中获取第3行,将其拆分并获取第一个数字.

这是等效的python脚本:

fname = 'input.txt'

with file(fname) as f:
    lines = f.read().splitlines()
    linegroups = [lines[i:i+3] for i in range(0, len(lines), 3)]
    nums = [linegroup[2].split()[0] for linegroup in linegroups]

with file('output2.txt', 'w') as f:
    f.write('\n'.join(nums))    
Run Code Online (Sandbox Code Playgroud)

Python不具备这样的一个衬里.在上面的脚本中,第一行代码将文件读入行列表,下一行将行分组为3组,下一行创建一个列表,其中包含每个组的每个最后一行的第一个数字.它与Scala代码非常相似,只是它的运行速度要快得多.

python脚本在我的笔记本电脑上运行不到一秒钟,而Scala程序运行15秒!我注释掉了将结果保存到文件的代码,持续时间降到了5秒,这仍然太慢了.另外我不明白为什么将数字保存到文件需要这么长时间.当我处理更大的文件时,python脚本运行了几秒钟,而Scala程序的运行时间是几分钟,我无法用来分析我的文件.

我很感激你对这个问题的建议.谢谢

Kev*_*ght 10

我冒昧地清理代码,这应该通过避免初始的mkString更高效地运行,不需要正则表达式来执行空白分割,而不是在写出结果之前预先聚合结果.我还使用了更好的自我记录方法:

val fname = "input.txt"
val lines = (Source fromFile fname).getLines
val counters =
  (lines grouped 3 withPartial false) map { _.last takeWhile (!_.isWhitespace) }

val f = new BufferedWriter(new FileWriter("output1.txt"))
f.write(counters mkString "\n")
f.close()
Run Code Online (Sandbox Code Playgroud)

警告,未经测试的代码

这在很大程度上是无关紧要的,取决于你的分析方式.如果您在指标中包含JVM启动时间,那么所有投注都将关闭 - 没有任何代码优化可以帮助您.

我通常也建议在你计时之前运行例程几百次来预热JVM,但面对文件I/O这不太实际.


huy*_*hjl 6

我将Kevin提供的版本定时进行了少量编辑(由于python版本不处理填充,因此删除了withPartial):

import scala.io.Source
import java.io.BufferedWriter
import java.io.FileWriter

object A extends App {

  val fname = "input.txt"
  val lines = (Source fromFile fname).getLines
  val counters =
    (lines grouped 3) map { _.last takeWhile (!_.isWhitespace) }

  val f = new BufferedWriter(new FileWriter("output1.txt"))
  f.write(counters mkString "\n")
  f.close()
}
Run Code Online (Sandbox Code Playgroud)

这里有60,000行时间:

$ time scala -cp classes A

real    0m2.823s

$ time /usr/bin/python A.py

real    0m0.437s
Run Code Online (Sandbox Code Playgroud)

拥有900,000行:

$ time scala -cp classes A

real    0m5.226s

$ time /usr/bin/python A.py

real    0m3.319s
Run Code Online (Sandbox Code Playgroud)

拥有2,700,000行:

$ time scala -cp classes A

real    0m9.516s

$ time /usr/bin/python A.py

real    0m10.635s
Run Code Online (Sandbox Code Playgroud)

之后scala版本优于python版本.所以似乎有些长时间是由于JVM初始化和JIT编译时间.

  • 同样有趣的事实:`awk'NR%3 == 0 {print $ 1}'input.txt> output.txt`优于那些相同输入文件的python和scala. (10认同)