2016/02/04

xargs -P 在 stdout 可能會遇到 race condition

爬 log 發現 log 格式不正確,而且還是經常發生,而手動追蹤時又找不到錯誤在哪裡:
find . -name '*2016-01*.log.gz' | xargs -I'{}' -P 4 zgrep keyword {} | awk ...

做了測試以後才發現 xargs -P 時,各個 process 只要有 stdout 就會和其他 process 打架,造成資料還沒寫完就被其他 process 插單,導致最後出來的資料不正確。



先建立二個檔案,儲存不同的二個資料。

0.test.log (每行 50 字):
.................................................
.................................................
.................................................
....

1.test.log (每行 50 字):
1111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111
...


接下來使用 xargs 來 echo 這二個檔案內容:
find . -name '*test.log' | xargs -I'{}' -P 2 cat {} > output.xargs.log

接下來寫個 script 來檢查 output.xargs.log 的內容是否都正確:
for LINE in `cat output.xargs.log `; do
    if [ 50 -lt ${#LINE} ]; then
        echo $LINE
    fi
done

結果會發現 output 有一行超過 50 個自得情況發生:
111111111111111111111111111111111111.................................................

而相同的情況下,parallel 就不會有相同的情況發生:
find . -name '*test.log' | parallel -j 2 cat {} > output.xargs.log

原因是 parallel 會將 jobs (process) 的 output 先 buffer 起來,等到整個 job 都結束以後在一起送到 stdout。若使用上述的範例改用 parallel 的操作來測試的話,可以發現不同 job 的 output 有被完全區隔開來,沒有混在一起:

...
.................................................
.................................................
.................................................
1111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111
1111111111111111111111111111111111111111111111111
...


總之,以後用到 xargs -P 時,要小心 race condition ... (暈)

沒有留言:

張貼留言