我有以下行shell腳本從文本文件中刪除雙引號「。SED,只選擇特定AWK或Python的shell腳本
sed 's/\"//g' old_file.txt > new_file.txt
還有一個AWK聲明從^分隔的文本文件列。
兩者都按預期工作的陳述。但是,當輸入文件的大小比數GB以上的服務器掛起。我想知道,如果蟒蛇可以做同樣的更高效。
更新:
它不停止服務器,但當我運行shell腳本時,託管在同一服務器上的mysql速度很慢。
我有以下行shell腳本從文本文件中刪除雙引號「。SED,只選擇特定AWK或Python的shell腳本
sed 's/\"//g' old_file.txt > new_file.txt
還有一個AWK聲明從^分隔的文本文件列。
兩者都按預期工作的陳述。但是,當輸入文件的大小比數GB以上的服務器掛起。我想知道,如果蟒蛇可以做同樣的更高效。
更新:
它不停止服務器,但當我運行shell腳本時,託管在同一服務器上的mysql速度很慢。
Python不太可能做得更快。通過一些工作,它可以以+/-相同的效率來做同樣的事情。除非你試圖做錯;因爲那樣會慢一些。
這兩個sed & awk以行模式運行。他們是相當I/O優化的,我認爲你可以改進。如果涉及到執行操作,Python腳本可能會更快,但在這種情況下,它與不太可能是相關的。
就管他們像@paxdiablo提示:
sed 's/"//g' old_file.txt | awk '...' > new_file.txt
或者,如果列的格式是很簡單的,你可以用更簡單的cut
取代awk
這將是更快:
sed 's/"//g' old_file.txt | cut -d' ' -f1-2,4 > new_file.txt
(例1,2欄爲& 4,空格分隔)
如果您需要的中間輸出,你可以把tee
在管道把它寫在此期間:
sed 's/"//g' old_file.txt | tee inter_file.txt | cut -d' ' -f1-2,4 > new_file.txt
但它可能是因爲這兩個inter_file.txt
和new_file.txt
將在同一時間被寫入實際效率較低。
好吧,現在我想我明白了問題所在。你的問題不是腳本不是足夠快的,因爲它獲得的速度是最快的。這是您的硬盤驅動器達到吞吐量限制,因此使用它的其他應用程序會延遲。你可以說這對於你的硬盤來說太快了。
一個解決方案是嘗試使用ionice
來降低優先級。它可能有所幫助,但它可能沒有任何區別。
ionice -c3 -p$$
給出當前shell或腳本的最低(空閒)I/O優先級。同樣,您可以使用以下給定優先級來啓動腳本:
ionice -c3 ./yourscript.sh
結果可能因使用的I/O調度程序而異。有些調度器會忽略這個,有些調度器可能會讓腳本變慢(每當mysql將要求I/O時)。
或者,您可以使用額外的程序來限制sed的吞吐量,並有效地降低速度併爲mysql提供一些空閒空間以適應。然而,您將需要測量哪些吞吐量是最優的您。
最後,如果以上都不是選項,那麼您可以跳到Python,並且每隔幾百或幾百行就添加time.sleep()
以停止腳本一段時間,讓mysql執行其工作。
「我認爲你可以改善這一點」 - 你可能想要重新思考:-)最起碼,每次調用讀取更多的數據總會讓你獲得更好的性能,因爲函數調用較少。 – paxdiablo 2012-08-17 09:08:01
@paxdiablo:你真的認爲正確編寫過濾器所需的時間有可能帶來如此巨大的收益,甚至值得考慮嗎?我認爲你通常不會每天在幾個演出文件上執行這些操作。 – 2012-08-17 09:10:12
你只需要寫過濾器一次,而且我爲你做了這個,所以這將是零次:-)顯然,OP認爲它很重要,否則就不會有問題。無論如何,它明顯超過了「sed」,這不僅僅是百分之幾,我們說的速度也是兩倍。然而,從問題來看,這一切都沒有意義,因爲它並不是被問到的問題。我將所有的表現內容留在我的答案中,但我的觀點是腳本不應該放在一個會影響「生產級別」內容的框中運行。 – paxdiablo 2012-08-17 09:16:10
這不太可能。既不會一次把整個文件sl到內存中,所以你的侷限性基本上就是磁盤I/O速率。
我收集它不是實際上掛起(完全停止),更有可能的是,它只是需要一些時間來處理更大的文件。
你可以嘗試幾件事。
首先,如果您要將new_file.txt
文件發送到awk
進程中,則根本不要創建中間文件。你應該能夠做到:
sed 's/\"//g' old_file.txt | awk 'some commands' >next_file.txt
其次,因爲它是一個相當簡單的替換,你會發現它的速度更快寫你自己的固定濾波器,而不是依靠其運行速度可能下降,因爲它sed
或python
腳本必須迎合一般情況。
換句話說,是這樣的:
create 1M buffer
read up to 1M from input
while not EOF:
go through data removing `"` characters.
write changed buffer to output.
read up to 1M from input
恰當的C代碼將是:
#include <stdio.h>
#include <errno.h>
static char buff[1000000];
int main (void) {
int sz;
char *src, *dst;
while ((sz = fread (buff, 1, sizeof(buff), stdin)) > 0) {
src = dst = buff;
while (sz-- >= 0) {
if (*src == '"') {
src++;
continue;
}
*dst++ = *src++;
}
sz = dst - buff;
if (fwrite (buff, sz, 1, stdout) != 1) {
fprintf (stderr, "Error %d writing data\n", errno);
return -1;
}
}
return 0;
}
這可能運行速度更快,由於事實,這是因爲當時的具體情況,但是,與所有的優化一樣,的措施,不要猜測!
在我的系統,在編譯代碼gcc -O3
紅粉結果如下,首先爲sed
:
pax> time (cat Photo_* | sed 's/"//g' >/dev/null)
real 0m0.094s
user 0m0.080s
sys 0m0.024s
pax> time (cat Photo_* | sed 's/"//g' >/dev/null)
real 0m0.097s
user 0m0.076s
sys 0m0.032s
pax> time (cat Photo_* | sed 's/"//g' >/dev/null)
real 0m0.095s
user 0m0.092s
sys 0m0.012s
pax> time (cat Photo_* | sed 's/"//g' >/dev/null)
real 0m0.096s
user 0m0.060s
sys 0m0.048s
pax> time (cat Photo_* | sed 's/"//g' >/dev/null)
real 0m0.095s
user 0m0.088s
sys 0m0.016s
那麼對於定製過濾器:
pax> time (cat Photo_* | ./qq >/dev/null)
real 0m0.030s
user 0m0.012s
sys 0m0.028s
pax> time (cat Photo_* | ./qq >/dev/null)
real 0m0.032s
user 0m0.008s
sys 0m0.032s
pax> time (cat Photo_* | ./qq >/dev/null)
real 0m0.030s
user 0m0.012s
sys 0m0.028s
pax> time (cat Photo_* | ./qq >/dev/null)
real 0m0.030s
user 0m0.012s
sys 0m0.028s
pax> time (cat Photo_* | ./qq >/dev/null)
real 0m0.030s
user 0m0.012s
sys 0m0.028s
所以平均system+user
和wallclock
倍是:
system+user wallclock
sed 0.1056 0.0954
custom 0.0400 0.0304
所以看起來,一個自定義過濾器可能會給你一個比一般情況下的性能優勢。對於測試數據,有三個匹配該通配符的文件,大小分別爲3427158
,5462472
和5921534
,所以總共大約14M。對於較大的輸入尺寸,使用3,791,657,984個字節(約4G)的單個文件,sed
(用戶+系統)時間爲27.037秒,而自定義時間爲9.020秒(均需要5個採樣和平均值)。
而且,正如你的問題的編輯,如果這個過程被放緩另一個更重要的過程,你應該不在那裏運行它。您應該同時使用nice
和ionice
a copy/ftp/rcp
命令,該命令將文件移至完全單獨的框中,您可以在其中運行腳本以達到心臟的內容而不會損害性能。
如果我跑那買了他們的表現我們的生產箱劇本,我有一半的網站的維護者,要求我的頭放在盤子裏:-)
這很可能是你目前的方法的改進,因爲您可以同時執行雙引號刪除和列選擇,並寫出最終結果。這樣你就可以避免向磁盤寫入一個非常大的中間文件。它也可能比將sed和awk放在管道中更快,因爲這需要一個額外的進程和一些同步開銷。
您不需要同時使用sed
和awk
;只需使用awk
即可。
假設你想要的第3列:
awk -F'^' '{gsub(/"/, "", $3); print $3;}' huge_data_file
這有許多,如不需要SED的優勢,管道,中間文件等。此外,更換"
只是做了數據包含在所需列中,而不是整行。
我測試了上含有6440萬線,包括這個數據重複的2.1G文件(不知道數據重複玷污我的測試):
"blah"^"blah blah"^"test1 ""^stuff
"blah"^"blah blah"^"test2 ""^stuff
"blah"^"blah blah"^"test3"^stuff
"blah"^"blah blah"^"test4^stuff^
$ time awk -F'^' '{gsub(/"/, "", $3); print $3;}' huge_data_file >/dev/null
real 2m31.706s
user 2m29.745s
sys 0m0.953s
否「掛起」。虛擬內存使用量不超過105MB。當然,您的服務器上的實際性能可能會有所不同。
[編輯]
對於比較:
$ time sed -e 's/"//g' huge_data_file | awk -F'^' '{ print $3;}' >/dev/null
real 2m9.723s
user 3m34.355s
sys 0m3.585s
從而有效魚雷,我的 「非sed的」 解決方案,雖然它需要兩倍的內存。
中取決於你的實現! – 2012-08-17 08:12:23
您的awk語句是否在'new_file.txt'上運行,或者它是否在sed命令的管道中? – 2012-08-17 08:14:51
sed輸出未被傳送到awk。它直接在new_file.txt上運行 – shantanuo 2012-08-17 08:16:30