簡體   English   中英

如何在不耗盡內存的情況下刪除Powershell中的重復項?

[英]How can I remove duplicates in Powershell without running out of memory?

我目前正在Windows Powershell中使用此命令從簡單的1行CSV中刪除重復項。

gc combine.csv | sort | get-unique > tags.cs

每當我在一個150mb的CSV(2000萬行猜測 )上運行它時,任務管理器會顯示Powershell占用所有可用內存(32GB)然后使用虛擬內存。 我也讓腳本運行了大約一個小時,但它沒有完成。 我發現這很奇怪,因為在excel中,通常需要幾秒鍾才能從我的1M行CSVS中刪除重復項。 有關如何處理這個的任何建議?

你可以嘗試:

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)

這是我在23秒內測試20M隨機數文件和~1.5GB內存。 如果它們確實需要排序,請使用SortedSet而不是HashSet ,它在5分鍾內運行並且<2GB內存。 雖然您的代碼仍在運行,目前已通過15GB。

編輯:tiberriver256評論說, [System.IO.File]::ReadLines ,而不是ReadAllLines可以前的文件完成了讀取流傳輸; 它返回一個枚舉器而不是所有行的最終數組。 在HashSet案例中,這會將運行時間從12.5秒降低到11.5秒 - 它變化太大而無法確定,但它似乎有所幫助。

Excel旨在處理有效的文件(顯然?我實際上有點驚訝)。

您的代碼的主要問題是您正在對它進行排序。 我知道你這樣做是因為Get-Unique需要它,但Sort-Object工作方式是它需要收集內存中發送到它的每個項目(在這種情況下,文件的每一行)以便實際做那種。 與文件不同,它不只是將其存儲為平面內存,而是將其存儲為N個字符串,其中N是文件中的行數,以及這些內存中字符串的所有開銷。 正如TessellatingHeckler指出的那樣,它似乎與排序有關,而不是存儲!

您可能希望確定給定的行在處理時是否唯一,因此您可以立即丟棄它。

為此,我會推薦套裝。 特別是一個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的文件上進行測試,其中只有26個是獨一無二的,只需要超過一分鍾,並且沒有明顯影響RAM。

大約一半行獨特的同一文件大約需要2分鍾,並使用大約2 GB的RAM(使用SortedSet需要2.5分鍾以上,大約2.4 GB)。

同樣的后一個文件,即使簡化了| sort | gu | sort | gu | sort | gu to | sort -Unique | sort -Unique在~10秒內使用超過5 GB的RAM。

如果你開始使用StreamReader.ReadLinefor循環以及其他一些東西,你可能會擠出更多的性能,但我會為你留下一個練習。

似乎在大多數實現中,在最好的情況下,使用的RAM量將高度依賴於有多少項是唯一的(更多唯一項意味着更多RAM)。

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秒。

從這里的類似問題中獲得一些額外的詭計( 在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。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM