我当前在Windows Powershell中使用此命令从简单的1行CSV中删除重复项。
gc combine.csv | sort | get-unique > tags.cs
每当我在150mb CSV(2000万行猜测)上运行它时,任务管理器都会显示Powershell耗尽所有可用内存(32GB),然后使用虚拟内存。我还让脚本运行了大约一个小时,并且没有完成。我发现这很奇怪,因为在excel中通常需要几秒钟的时间才能从我的1M行CSVS中删除重复项。有关如何处理此问题的任何建议?
答案 0 :(得分:8)
您可以尝试:
Get-Content combine.csv -ReadCount 1000 |
foreach-object { $_ } |
Sort-Object -Unique |
Set-Content tags.cs
({gc combine.csv -read 1kb | % { $_ } | sort -uniq | sc tags.cs
)
但是我认为您会遇到同样的问题。如果您想要更快的结果,并且不需要对其进行排序,则只需免费复制它们即可:
$Lines = [System.Collections.Generic.HashSet[string]]::new()
$Lines.UnionWith([string[]][System.IO.File]::ReadAllLines('c:\path\to\combine.csv'))
[System.IO.File]::WriteAllLines('c:\path\to\tags.cs', $Lines)
在我测试的20M随机数字文件中运行了23秒,内存达到约1.5GB。如果确实需要对它们进行排序,请使用SortedSet
而不是HashSet
,它们运行5分钟且内存不足2GB。当您的代码仍在运行并且当前超过15GB时。
编辑: tiberriver256 的评论是,[System.IO.File]::ReadLines
而不是ReadAllLines
可以在文件读取完成之前进行流传输;它返回一个枚举数,而不是所有行的最终数组。在HashSet的情况下,这会使运行时间从12.5s稍微降低到11.5s-不确定太多,但这确实有所帮助。
答案 1 :(得分:5)
Excel旨在有效处理大型文件(显然吗?我实际上有点惊讶)。
代码的主要问题是您正在对其进行排序。我知道您这样做是因为Get-Unique
需要它,但是Sort-Object
的工作方式是它需要将发送到其中的每个项目(在本例中是文件的每一行)收集到内存中为了实际进行排序。 与文件不同,它不仅将其存储为平面存储器,还存储为 N 个字符串,其中 N 是文件中的行数,正如TessellatingHeckler指出的那样,它似乎更多地与排序有关,而不是与存储有关!
您可能希望在处理给定行时确定给定行是否唯一,因此可以立即将其丢弃。
为此,我将推荐Sets。特别是HashSet,或者,如果您需要对它进行排序,则特别是SortedSet。
代码的简单转换:
Get-Content combine.csv |
ForEach-Object -Begin {
$h = [System.Collections.Generic.HashSet[String]]::new()
} -Process {
if ($h.Add($_)) {
$_
}
} |
Set-Content tags.cs
对我来说,在650 MB的文件上用〜4M行进行测试,其中只有26个是唯一的,这花了一个多分钟,并且对RAM没有明显影响。
同一文件中大约一半的行是唯一的,耗时约2分钟,并使用了约2 GB的RAM(使用SortedSet
则花费了2.5分钟多一点的时间,约占2.4 GB)。
即使从| sort | gu
简化为| sort -Unique
到后者,该文件仍在大约10秒内使用了5 GB以上的RAM。
如果您开始使用StreamReader.ReadLine
和for
循环以及其他一些东西,您可能会挤出更多的性能,但我将为您保留这一练习。
似乎在大多数实现中,在最佳情况下,RAM的使用量将高度依赖于唯一项的数量(更多唯一项意味着更多RAM)。
答案 2 :(得分:4)
Get-Content和stdio >
都很慢。 .Net可能会给您带来更好的性能。
尝试:
$stream = [System.IO.StreamWriter] "tags.csv"
[System.IO.File]::ReadLines("combine.csv") | get-unique | sort | % { $Stream.writeline($_) }
$Stream.close()
在我自己的带有4列1,000,000行csv的盒子上进行测试,我在22秒时达到了650MB的内存利用率。使用get-content和>
运行相同的csv需要2GB内存和60秒。
从此处类似的问题中{Sort very large text file in PowerShell)还具有一些其他技巧,您可以通过将数据强制转换为哈希集以获取唯一值,然后转换为列表并运行sort方法来进一步减少时间比PowerShell的Sort-Object快一点。
$stream = [System.IO.StreamWriter] "tags.csv"
$UniqueItems = [system.collections.generic.list[string]]([System.Collections.Generic.HashSet[string]]([System.IO.File]::ReadLines("combine.csv")))
$UniqueItems.sort()
$UniqueItems | % { $Stream.writeline($_) }
$Stream.close()
在同一数据集上使用它,我能够在1秒内完成144MB的内存使用。