>"が遅くなりますか?">

ファイルサイズが大きくなるほど、Linuxリダイレクト">>"が遅くなりますか?

ファイルサイズが大きくなるほど、Linuxリダイレクト>"が遅くなりますか?">

いくつかの分析を実行し、別のファイルで実行するいくつかのコマンドを準備(書き込み)するシェルスクリプトがあります。

だから私は次のようなものを持っています:

echo my_command_to_run >> /tmp/file_command_to_run.txt

プログラムがどんどん遅くなると思います。 ファイルが大きい場合(〜3M行)、プログラムに時間がかかりますか?

また、メモリに何かを保存しているので、これが問題の原因かもしれませんが、出力を別のファイルにリダイレクトする必要があるかどうかを知りたいです。 (例:2000行のファイルを複数作成)


編集:私のスクリプトは、約64M(数百万)のファイルをより良いスキーマに移動する準備をしています。それで、私はさまざまな「構造化された」フォルダをすべて見て、移動する準備をしました。

メモリには次の配列があります。

topic1 -> /path/to/my/folder
topic1_number_of_files -> nb

したがって、複数の項目(最大〜4'000)があるため、私の配列も大きくなります。

そうでない場合、ジョブの実行は常に同じです。私の配列とファイルだけが大きくなっています。


EDIT2:以下は私のスクリプトです。

メモ:

  • 最大100,000個のファイルを含む複数のフォルダがあります。
  • 次のものがあります。フォルダ1 - >(source1__description1、source1__description2、source2__description3)

目標:次のことを行ってください。

  • ソース1/フォルダ1 ->(ソース1__説明1、ソース1__説明2)
  • ソース2/フォルダ1 ->(ソース2__説明3、...)

現在のパフォーマンス:

14時間で約900,000行が挿入されました。 <=>すべての移動コマンドを準備するのに約40日かかります。

#!/bin/bash

argument=$1

if [[ -n "$argument" ]] && [[ -e $argument ]]; then
    html_folder=$argument
    echo "We will move [folder]/files from your parameters: '$html_folder'"
else
    html_folder="/var/files/html_files/"
    echo "NO PARAMETER (or folder does not exist) - We will move [folder]/files from $html_folder"
fi

######################## create the list ########################
filename="/var/files/html_files/list_folder.txt" # list generated with  ls -1 -f (this doesn't take everything in memory)
ls -1 -fp $html_folder |  grep '/$' |  grep 'folder'> "$filename"
#################### END create the list ########################


echo " "


# --------------------------------------------------------------
# -------------- Global variables for moving part --------------
# --------------------------------------------------------------
    # Variables for storing the folder/files tree
    declare -A folder_array         # array of folder '/files/publisher_html/10.3390' => 4 (i.e.: 4 folders for mdpi)
    declare -A folder_files_array   # array of files in last folder '/files/publisher_html/10.3390' => 51 (i.e.: 51 files in the 4th folders for mdpi)
    storageFolder="/files/publisher_html/"
    nb_limit=100000 # max number of file per folder
    file_nb=0
    current_folder=""
# --------------------------------------------------------------
# --------------------------------------------------------------
# --------------------------------------------------------------


# --------------------------------------------------------------
# -------------- Global functions for moving part --------------
# --------------------------------------------------------------

    countNumberOfFilesPerFolder () {
        nb=0
        if [[ -e $1 ]]; then        
            nb=$(ls -1fp $1 |  grep -v '/$' | wc -l )        
        fi
        echo $nb
    }

    createFolderIfNeeded () {
        # $1  # first arg (/path/to/htmlfiles/10.3390)
        tmp_folder=""
        nb_folder=1
        nb_files=0

        if [[ ! -e $1 ]]; then # if folder doesn't exist
            sudo mkdir -p "$1/folder$nb_folder" ; # create the folders if don't exist
        else
            #echo "THE FOLDER $tmp_folder ALREADY EXISTED...BE AWARE!!!"
            if [[ -e ${folder_array[$1]} ]]; then
                nb_folder=${folder_array[$1]} # take the value from memory if available
            else
                nb_folder=$(ls -1f $1 | grep folder | wc -l )
            fi

            if (($nb_folder==0)); then # if no subfolder for the publisher folder
                nb_folder=1
                nb_files=0
                sudo mkdir -p "$1/folder$nb_folder" # simply create the first folder
            else
                # if [[ -e ${folder_files_array[$1]} ]]; then
                if [[ ${folder_files_array[$1]} ]]; then
                    nb_files=${folder_files_array[$1]}  # value from memory
                    #echo "value from MEEEEEM: $1 => $nb_files"
                else
                    nb_files=`countNumberOfFilesPerFolder "$1/folder$nb_folder"`
                    #echo "value from COOOOOOUNT: $1 => $nb_files"
                fi

                if (($nb_files >= $nb_limit)); then # create a new folder + reset memory value
                    ((nb_folder++))
                    nb_files=0
                    sudo mkdir -p "$1/folder$nb_folder"
                    #`createFolderIfNeeded "$1/folder$nb_folder"` # NO CORRECT -> will create a subfolder
                fi            
            fi       
        fi

        #((nb_files++))
        folder_files_array[$1]=$nb_files
        folder_array[$1]=$nb_folder

        current_folder="$1/folder$nb_folder" # change the global variable
    }

    extractPrefix() {
        whotest[0]='test' || (echo 'Failure: arrays not supported in this version of
    bash.' && exit 2)
        array=(${1//__/ })
        prefix=${array[0]}
        echo $prefix
    }
# --------------------------------------------------------------
# --------------------------------------------------------------
# --------------------------------------------------------------


toMoveFolder=$html_folder"toMove/"
toMoveFileIndex=1
toMoveCmdNumber=0
maxCmdInFile=2000
if [[ ! -e $toMoveFolder ]]; then # if folder doesn't exist
    sudo mkdir -p $toMoveFolder ; # create the folders
fi

cd $html_folder

while read -r folder # for each folder
do
    if [[ -e $folder ]]; then        
        echo "Will manage folder: $folder"


# ---------------------------------------------------------------------------------------------------
# -------------------------------------- MOVE INDIVIDUAL FILES --------------------------------------
# ---------------------------------------------------------------------------------------------------

    argument=$html_folder$folder
    cpt=0
    #argument=$1

    if [[ -n "$argument" ]] && [[ -e $argument ]]; then
        html_files_folder=$argument
    else
        html_files_folder="/var/files/html_files/html_files/"
    fi

    ######################## create the list ########################

    htmlList="/var/files/html_files/list_html.txt" # list generated with  ls -1 -f (this doesn't take everything in memory)
    ls -1f $html_files_folder > "$htmlList" # no need to exclude the "." and ".." (we exclude from the foreach)
    #################### END create the list ########################

    echo " "


    current_folder=$storageFolder # probably useless

    while read -r line
    do
        name=$line

        if [[ $name != "." ]] && [[ $name != ".." ]]; then # don't take the folder itself
            prefix=`extractPrefix $name`
            if [ -n $prefix ]; then
                # change the global $current_folder
                # + create new subfolder if needed
                # + increment nb of files in folder
                createFolderIfNeeded $storageFolder$prefix
                ((cpt++))

                if(( $toMoveCmdNumber >= $maxCmdInFile )); then
                    toMoveCmdNumber=0
                    ((toMoveFileIndex++))
                fi

        echo "sudo mv $html_files_folder$name $current_folder/$name" | sed -r 's/[\(\)]+/\\&/g' >> $toMoveFolder"command_"$toMoveFileIndex".txt"
                ((toMoveCmdNumber++))

                ((folder_files_array[$storageFolder$prefix]++))

                if (( $cpt % 50 == 0 ));then
                    echo ""
                    echo "Remind: folder -> $current_folder/"
                    echo "${#folder_array[@]} publishers in memory!"
                fi

                echo "#$cpt - $name (${folder_files_array[$storageFolder$prefix]} files)"
            else
                echo "ERROR -> $name has not been moved as expected"
            fi        
       fi

    # >> $toMoveFolder"file"$toMoveFileIndex".txt" # <== does not take the toMoveFileIndex variation in consideration
    done < "$htmlList" # useful if we use the while

    echo "Folder $html_files_folder has been processed"
    echo " "


# ---------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------
# ---------------------------------------------------------------------------------------------------


    else  # END  if [[ -e $folder ]]; then
        echo " "; echo "ERROR -> folder $folder does NOT exist!"; echo " "
        continue
    fi

done < "$filename" # useful if we use the while

echo "The script to prepare the move of the html files FROM FOLDER in other folders finished!"
echo " "
echo " "
echo "FOLDER ARRAY AT THE END: "
    for i in "${!folder_array[@]}"; do echo "folder  : $i => nb_folder: ${folder_array[$i]} / nb__file in last folder: ${folder_files_array[$i]}"; done

echo " "
echo " "
echo "This is the end of the script"

そしてパーティション:

$df -h
/dev/sdb1         2.0T  370G  1.7T  19% /var/files
X.X.X.X:/files     11T  2.8T  7.2T  28% /files

最後の修正:

さらなる分析の後、/var/files/html_files/が/files/html_files/へのシンボリックリンクであるため、ソースとターゲットは実際には同じ(リモート)サーバーであることがわかりました。 「リモート」サーバーでスクリプトを実行しましたが、はるかに速いようです。

あなたの助けと興味深いコメントに感謝します!

ベストアンサー1

出力を別のファイルにリダイレクトする必要があるかどうか疑問に思います。 (例:2000行のファイルを複数作成)

より多くのファイルに分割しても必ずしも実行速度が速くなるわけではありません。 3つの簡単なテストケースがこの点を示しています。これら3つのケースはそれぞれ300万行を印刷します。実行速度が最も速いものから最も遅いものの順にリストされています。

  1. ループ外からの1回のリダイレクト

    for i in $(seq $((3000000/2000))); do seq 2000; done > file
    
  2. ループ内で同じファイルに追加

    for i in $(seq $((3000000/2000))); do seq 2000 >> file; done
    
  3. 出力を複数のファイルに分割

    for i in $(seq $((3000000/2000))); do seq 2000 > file$i; done
    

以降のコマンドは、常に前のコマンドよりも多くのユーザーとシステム時間を消費します。

これから、この単純なケースでは、より多くのファイルに分割することはパフォーマンスの向上を保証しないと結論付けることができます。事実はその逆です。

I/O オペランド

パフォーマンスはファイルサイズだけでなく、IO操作の数によって異なります。追加(>>)すると、ファイルの終わりを見つけるためにより多くのI / O呼び出しが発生します。

最初のスクリプトはi / o操作を実行します(>>)。外部サイクルfor:

$ cat outloop.sh
#!/bin/sh
>file
for i in $(seq 1 ${1:?})
do
    echo $i
done >> file

一方、スクリプトは>>反復ごとにi / o操作()を実行します。~へサイクルfor:

$ cat inloop.sh
#!/bin/sh
>file
for i in $(seq 1 ${1:?})
do
    echo $i >> file
done

実行して比較して、ワーカーの場所がパフォーマンス>>にどのような影響を与えるかを確認します。

$ x=500000; time sh outloop.sh $x; time sh inloop.sh $x; 

real    0m1.227s
user    0m0.389s
sys     0m0.859s

real    0m2.996s
user    0m0.809s
sys     0m2.197s

場所リダイレクト演算子外部私のシステムで500,000行を書くと、ループはパフォーマンスを2倍にします。

おすすめ記事