【发布时间】:2017-07-14 14:28:16
【问题描述】:
我看过一些关于此的帖子,没有真正的答案或过时的答案,所以我想知道是否有任何新的解决方案。我有一个巨大的 CSV 我需要读入。我不能在它上面调用 open() ,因为它会杀死我的服务器。我别无选择,只能使用 .foreach()。
这样做,我的脚本需要 6 天才能运行。我想看看我是否可以通过使用线程并将任务分成两个或四个来减少它。因此,一个线程读取第 1-n 行,而一个线程同时读取第 n+1-end 行。
所以我需要能够在一个线程中只读取文件的后半部分(稍后如果我将其拆分为更多线程,则只需通过特定行的特定行)。
Ruby 中有没有办法做到这一点?这可以从某一行开始吗?
CSV.foreach(FULL_FACT_SHEET_CSV_PATH) do |trial|
编辑: 只是想知道我的一个线程是什么样子的:
threads << Thread.new {
CSV.open('matches_thread3.csv', 'wb') do |output_csv|
output_csv << HEADER
count = 1
index = 0
CSV.foreach(CSV_PATH) do |trial|
index += 1
if index > 120000
break if index > 180000
#do stuff
end
end
end
}
但正如您所见,它必须迭代文件,直到它开始记录 120,000。因此,目标是通过从第 120,000 行开始读取来消除读取第 120,000 行之前的所有行。
【问题讨论】:
-
6 天真的很长。即使您将任务并行化为 6 个进程,这也至少需要一天时间。我认为您真的应该找到提高速度的方法,也许可以提供更多关于我们可以提供帮助的每一行的过程的详细信息。
-
CSV.forEach是一种符合 ruby 标准的快速方法。因此,仅通过优化它而不丢掉大量 CPU,您可能不会获得很大的改进。我建议你尝试用 Python 或其他语言来解析它。 -
@Nerve 除非 CSV 存在缺陷,否则将语言从 Ruby 切换到 Python 不会有太多好处。
-
@MarkThomas 整个过程现在需要 3 天(因为我删除了一些搜索词)。看起来它以每行 2.5 秒的速度读取每一行。但是我在那里有遍历另一个 CSV 的逻辑,并且其中有更多循环。这是一种匹配算法,可以进行转储以最终上传到数据库。通常我会为此使用 db 和类似 solr 的东西,但这不是我的项目。我只有这一项任务。
-
听起来你有一个 N+1 风格的问题。第二个 CSV 是否适合内存?否则,也许您应该生成后台作业。
标签: ruby-on-rails ruby multithreading csv foreach