2012-08-17 66 views
0

我有以下行shell腳本從文本文件中刪除雙引號「。SED,只選擇特定AWK或Python的shell腳本

sed 's/\"//g' old_file.txt > new_file.txt 

還有一個AWK聲明從^分隔的文本文件列。

兩者都按預期工作的陳述。但是,當輸入文件的大小比數GB以上的服務器掛起。我想知道,如果蟒蛇可以做同樣的更高效。

更新:

它不停止服務器,但當我運行shell腳本時,託管在同一服務器上的mysql速度很慢。

+0

中取決於你的實現! – 2012-08-17 08:12:23

+0

您的awk語句是否在'new_file.txt'上運行,或者它是否在sed命令的管道中? – 2012-08-17 08:14:51

+0

sed輸出未被傳送到awk。它直接在new_file.txt上運行 – shantanuo 2012-08-17 08:16:30

回答

3

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.txtnew_file.txt將在同一時間被寫入實際效率較低。


好吧,現在我想我明白了問題所在。你的問題不是腳本不是足夠快的,因爲它獲得的速度是最快的。這是您的硬盤驅動器達到吞吐量限制,因此使用它的其他應用程序會延遲。你可以說這對於你的硬盤來說太快了。

一個解決方案是嘗試使用ionice來降低優先級。它可能有所幫助,但它可能沒有任何區別。

ionice -c3 -p$$ 

給出當前shell或腳本的最低(空閒)I/O優先級。同樣,您可以使用以下給定優先級來啓動腳本:

ionice -c3 ./yourscript.sh 

結果可能因使用的I/O調度程序而異。有些調度器會忽略這個,有些調度器可能會讓腳本變慢(每當mysql將要求I/O時)。

或者,您可以使用額外的程序來限制sed的吞吐量,並有效地降低速度併爲mysql提供一些空閒空間以適應。然而,您將需要測量哪些吞吐量是最優的您。

最後,如果以上都不是選項,那麼您可以跳到Python,並且每隔幾百或幾百行就添加time.sleep()以停止腳本一段時間,讓mysql執行其工作。

+0

「我認爲你可以改善這一點」 - 你可能想要重新思考:-)最起碼,每次調用讀取更多的數據總會讓你獲得更好的性能,因爲函數調用較少。 – paxdiablo 2012-08-17 09:08:01

+0

@paxdiablo:你真的認爲正確編寫過濾器所需的時間有可能帶來如此巨大的收益,甚至值得考慮嗎?我認爲你通常不會每天在幾個演出文件上執行這些操作。 – 2012-08-17 09:10:12

+0

你只需要寫過濾器一次,而且我爲你做了這個,所以這將是零次:-)顯然,OP認爲它很重要,否則就不會有問題。無論如何,它明顯超過了「sed」,這不僅僅是百分之幾,我們說的速度也是兩倍。然而,從問題來看,這一切都沒有意義,因爲它並不是被問到的問題。我將所有的表現內容留在我的答案中,但我的觀點是腳本不應該放在一個會影響「生產級別」內容的框中運行。 – paxdiablo 2012-08-17 09:16:10

1

這不太可能。既不會一次把整個文件sl到內存中,所以你的侷限性基本上就是磁盤I/O速率。

我收集它不是實際上掛起(完全停止),更有可能的是,它只是需要一些時間來處理更大的文件。

你可以嘗試幾件事。

首先,如果您要將new_file.txt文件發送到awk進程中,則根本不要創建中間文件。你應該能夠做到:

sed 's/\"//g' old_file.txt | awk 'some commands' >next_file.txt 

其次,因爲它是一個相當簡單的替換,你會發現它的速度更快寫你自己的固定濾波器,而不是依靠其運行速度可能下降,因爲它sedpython腳本必須迎合一般情況。

換句話說,是這樣的:

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+userwallclock倍是:

  system+user wallclock 
sed   0.1056  0.0954 
custom  0.0400  0.0304 

所以看起來,一個自定義過濾器可能會給你一個比一般情況下的性能優勢。對於測試數據,有三個匹配該通配符的文件,大小分別爲3427158,54624725921534,所以總共大約14M。對於較大的輸入尺寸,使用3,791,657,984個字節(約4G)的單個文件,sed(用戶+系統)時間爲27.037秒,而自定義時間爲9.020秒(均需要5個採樣和平均值)。


而且,正如你的問題的編輯,如果這個過程被放緩另一個更重要的過程,你應該在那裏運行它。您應該同時使用niceionice a copy/ftp/rcp命令,該命令將文件移至完全單獨的框中,您可以在其中運行腳本以達到心臟的內容而不會損害性能。

如果我跑那買了他們的表現我們的生產箱劇本,我有一半的網站的維護者,要求我的頭放在盤子裏:-)

+0

這是一個很好的答案,然後你添加了'你自己的固定過濾器'... – 2012-08-17 08:27:38

+0

答案依然存在。管它而不是創建一個臨時文件,以便大部分內容都發生在內存中。衡量一個自定義過濾器是否比一般情況過濾器工作得更快。如果是這樣,請使用自定義過濾器,如果沒有,請將其丟棄。但是我必須說,我發現使用這種方法有了改進。 – paxdiablo 2012-08-17 08:35:32

+0

@MichałGórny,你可能想檢查更新,一個自定義過濾器可以_definitely_勝過一般情況下,相當多。 – paxdiablo 2012-08-17 09:05:42

1

這很可能是你目前的方法的改進,因爲您可以同時執行雙引號刪除和列選擇,並寫出最終結果。這樣你就可以避免向磁盤寫入一個非常大的中間文件。它也可能比將sed和awk放在管道中更快,因爲這需要一個額外的進程和一些同步開銷。

0

您不需要同時使用sedawk;只需使用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的」 解決方案,雖然它需要兩倍的內存。