GNU/Linux >> Linux の 問題 >  >> Linux

Linux でファイルをコピーする最も効率的な方法

Linux> 2.6.17、splice() を使用することがわかっている場合 Linux でゼロコピーを行う方法です:

 //using some default parameters for clarity below. Don't do this in production.
 #define splice(a, b, c) splice(a, 0, b, 0, c, 0)
 int p[2];
 pipe(p);
 int out = open(OUTFILE, O_WRONLY);
 int in = open(INFILE, O_RDONLY)
 while(splice(p[0], out, splice(in, p[1], 4096))>0);

残念ながら、sendfile() は使用できません ここでは、宛先がソケットではないためです。 (名前 sendfile() send() から来ています + "ファイル").

ゼロコピーの場合、splice() を使用できます @Daveの提案どおり。 (ただし、ゼロ コピーではなく、ソース ファイルのページ キャッシュから宛先ファイルのページ キャッシュへの「1 つのコピー」になります。)

しかし... (a) splice() Linux 固有です。 (b) ポータブル インターフェースを正しく使用すれば、ほぼ確実に同じように使用できます。

つまり、open() を使用します。 + read() + write() 小さい 一時バッファ。 8Kをお勧めします。したがって、コードは次のようになります:

int in_fd = open("source", O_RDONLY);
assert(in_fd >= 0);
int out_fd = open("dest", O_WRONLY);
assert(out_fd >= 0);
char buf[8192];

while (1) {
    ssize_t read_result = read(in_fd, &buf[0], sizeof(buf));
    if (!read_result) break;
    assert(read_result > 0);
    ssize_t write_result = write(out_fd, &buf[0], read_result);
    assert(write_result == read_result);
}

このループでは、in_fd ページ キャッシュから CPU L1 キャッシュに 8K をコピーし、L1 キャッシュから out_fd ページ キャッシュに書き込みます。次に、L1 キャッシュのその部分をファイルの次の 8K チャンクで上書きします。最終的な結果は、buf のデータは 実際にメイン メモリに格納されることはありません (おそらく最後に 1 回を除く)。システム RAM の観点からは、これは「ゼロコピー」 splice() を使用するのと同じくらい良いです .さらに、どの POSIX システムにも完全に移植可能です。

ここでは小さなバッファが重要であることに注意してください。典型的な最近の CPU は、L1 データ キャッシュ用に 32K 程度を持っているため、バッファを大きくしすぎると、このアプローチは遅くなります。おそらく、はるかに遅くなります。したがって、バッファは「数キロバイト」の範囲に収めてください。

もちろん、ディスク サブシステムが非常に高速でない限り、メモリ帯域幅はおそらく制限要因ではありません。 posix_fadvise をお勧めします あなたが何をしようとしているのかをカーネルに知らせるために:

posix_fadvise(in_fd, 0, 0, POSIX_FADV_SEQUENTIAL);

これにより、先読み機構が非常に積極的であるべきだというヒントが Linux カーネルに与えられます。

posix_fallocate を使用することもお勧めします 宛先ファイルのストレージを事前に割り当てます。これにより、ディスクが不足するかどうかが事前にわかります。また、最新のファイル システム (XFS など) を備えた最新のカーネルの場合、宛先ファイルの断片化を減らすのに役立ちます。

最後にお勧めするのは mmap です .これは通常、TLB スラッシングのおかげで、最も遅いアプローチです。 (「transparent hugepages」を備えたごく最近のカーネルでは、これが軽減される可能性があります。最近試したことはありません。しかし、以前は非常に悪かったことは確かです。そのため、わざわざ mmap をテストするだけです。 ベンチマークに十分な時間があり、最新のカーネルを使用している場合。)

[更新]

splice かどうかについてのコメントにいくつかの質問があります あるファイルから別のファイルへのゼロコピーです。 Linux カーネル開発者は、これを「ページ盗用」と呼んでいます。 splice の両方の man ページ カーネルソースのコメントによると、SPLICE_F_MOVE flag はこの機能を提供する必要があります。

残念ながら、SPLICE_F_MOVE のサポートは 2.6.21 (2007 年) で削除され、置き換えられることはありませんでした。 (カーネル ソースのコメントは更新されていません。) カーネル ソースを検索すると、 SPLICE_F_MOVE が見つかります。 実際にはどこにも参照されていません。私が見つけた最後のメッセージ (2008 年以降) には、「交換を待っています」と書かれています。

結論は splice です あるファイルから別のファイルへの呼び出し memcpy データを移動します。 そうではない ゼロコピー。これは、 read を使用してユーザー空間で実行できるよりもはるかに優れているわけではありません /write バッファが小さいので、標準の移植可能なインターフェースに固執することもできます。

「ページ盗用」が Linux カーネルに再び追加された場合、splice の利点は はるかに大きいでしょう。 (そして今日でも、宛先がソケットの場合、真のゼロコピーが得られ、splice になります。 より魅力的です。)しかし、この質問の目的のために、splice あまり買わない。


Linux
  1. ファイルの内容を空にする最も効率的な方法は?

  2. Linux に AzCopy をインストールする – Azure でコピーする最速の方法

  3. Linux ターミナルでファイルの内容をクリップボードにコピーする

  1. pscp Windows から Linux にリモートでファイルをコピーする

  2. Windows から Linux にファイルをコピーする

  3. ETAを使用したLinuxファイルのコピー?

  1. Linuxターミナルでファイルをコピーする

  2. Linuxでファイルとディレクトリを隠す簡単な方法

  3. gcp –Linux用の高度なファイルコピーユーティリティ