[解決済み] なぜC++はPythonよりもstdinからの行の読み込みが遅いのですか?
質問
PythonとC++を使用して標準入力から文字列の行を読むことを比較したかったのですが、私のC++コードが同等のPythonコードよりも一桁遅く実行されるのを見てショックを受けました。私のC++は錆びつき、私はまだPythonの専門家ではないので、私が何か間違ったことをしているか、私が何かを誤解しているかどうか教えてください。
(
TLDRの答え。
という文言を入れる。
cin.sync_with_stdio(false)
を使うか、あるいは
fgets
の代わりに
TLDRの結果。 私の質問の一番下までスクロールして、表を見てください)
C++のコードです。
#include <iostream>
#include <time.h>
using namespace std;
int main() {
string input_line;
long line_count = 0;
time_t start = time(NULL);
int sec;
int lps;
while (cin) {
getline(cin, input_line);
if (!cin.eof())
line_count++;
};
sec = (int) time(NULL) - start;
cerr << "Read " << line_count << " lines in " << sec << " seconds.";
if (sec > 0) {
lps = line_count / sec;
cerr << " LPS: " << lps << endl;
} else
cerr << endl;
return 0;
}
// Compiled with:
// g++ -O3 -o readline_test_cpp foo.cpp
Pythonの同等品です。
#!/usr/bin/env python
import time
import sys
count = 0
start = time.time()
for line in sys.stdin:
count += 1
delta_sec = int(time.time() - start_time)
if delta_sec >= 0:
lines_per_sec = int(round(count/delta_sec))
print("Read {0} lines in {1} seconds. LPS: {2}".format(count, delta_sec,
lines_per_sec))
以下は私の結果です。
$ cat test_lines | ./readline_test_cpp
Read 5570000 lines in 9 seconds. LPS: 618889
$ cat test_lines | ./readline_test.py
Read 5570000 lines in 1 seconds. LPS: 5570000
Mac OS X v10.6.8 (Snow Leopard) と Linux 2.6.32 (Red Hat Linux 6.2) の両方で試したことを書き添えておきます。前者はMacBook Proで、後者は非常に高性能なサーバーです。
$ for i in {1..5}; do echo "Test run $i at `date`"; echo -n "CPP:"; cat test_lines | ./readline_test_cpp ; echo -n "Python:"; cat test_lines | ./readline_test.py ; done
Test run 1 at Mon Feb 20 21:29:28 EST 2012
CPP: Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 2 at Mon Feb 20 21:29:39 EST 2012
CPP: Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 3 at Mon Feb 20 21:29:50 EST 2012
CPP: Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 4 at Mon Feb 20 21:30:01 EST 2012
CPP: Read 5570001 lines in 9 seconds. LPS: 618889
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
Test run 5 at Mon Feb 20 21:30:11 EST 2012
CPP: Read 5570001 lines in 10 seconds. LPS: 557000
Python:Read 5570000 lines in 1 seconds. LPS: 5570000
小さなベンチマークの追記とまとめ
完全を期すために、同じボックスで同じファイルをオリジナルの(同期した)C++コードで実行した場合の読み込み速度を更新しておこうと思いました。繰り返しますが、これは高速ディスク上の100M行のファイルに対するものです。以下は、いくつかの解決策/アプローチとの比較です。
解決方法
tl;dr: C++のデフォルト設定が異なるため、より多くのシステムコールを必要とします。
デフォルトでは
cin
は stdio と同期しており、入力バッファリングを回避しています。 これをmainの先頭に追加すると、パフォーマンスが大幅に改善されるはずです。
std::ios_base::sync_with_stdio(false);
通常、入力ストリームがバッファリングされている場合、一度に1文字ずつ読むのではなく、より大きなチャンクで読み込まれます。 これにより、一般的に比較的高価なシステムコールの数を減らすことができます。 しかし
FILE*
ベース
stdio
と
iostreams
は実装が別々であることが多く、したがってバッファも別々であるため、両者を併用すると問題が発生する可能性があります。 例えば
int myvalue1;
cin >> myvalue1;
int myvalue2;
scanf("%d",&myvalue2);
によってさらに多くの入力が読み込まれた場合
cin
が実際に必要な数よりも多い場合、2 番目の整数値は
scanf
関数は、それ自身の独立したバッファを持っています。 これでは、予期せぬ結果を招くことになる。
これを避けるために、デフォルトでは、ストリームは同期化された
stdio
. これを実現する一般的な方法の1つは
cin
を使用して、必要に応じて1文字ずつ読み取ります。
stdio
関数を使用します。 残念ながら、これには多くのオーバーヘッドが発生します。 少量の入力であれば大きな問題にはなりませんが、何百万行も読むとなると、性能上のペナルティは大きいです。
幸いなことに、ライブラリの設計者は、自分が何をしているかを知っていれば、この機能を無効にしてパフォーマンスを向上させることもできるはずだと判断し、そのような機能を提供するために
sync_with_stdio
というメソッドがあります。このリンクから(強調)。
同期をオフにすると、C++標準ストリームは独立してI/Oをバッファリングすることができるようになります。 場合によってはかなり速くなる .
関連
-
PythonによるLeNetネットワークモデルの学習と予測
-
ピローによる動的キャプチャ認識のためのPythonサンプルコード
-
Python百行で韓服サークルの画像クロールを実現する
-
[解決済み] Python 3で「1000000000000000 in range(1000000000000001)」はなぜ速いのですか?
-
[解決済み] Pythonの辞書からキーを削除するにはどうしたらいいですか?
-
[解決済み] 要素ごとの加算は、結合ループよりも分離ループの方がはるかに高速なのはなぜですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] Pythonでファイル名から拡張子を抽出する
-
[解決済み] Pythonのクラスはなぜオブジェクトを継承するのですか?
-
[解決済み] なぜPythonのコードは関数の中でより速く実行されるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Python 人工知能 人間学習 描画 機械学習モデル作成
-
Python カメの描画コマンドとその例
-
pythonサイクルタスクスケジューリングツール スケジュール詳解
-
python implement mysql add delete check change サンプルコード
-
pyCaret効率化乗算器 オープンソース ローコード Python機械学習ツール
-
FacebookオープンソースワンストップサービスpythonのタイミングツールKats詳細
-
[解決済み】OSError: [WinError 193] %1 は有効な Win32 アプリケーションではありません。
-
[解決済み】 NameError: グローバル名 'xrange' は Python 3 で定義されていません。
-
[解決済み】NameError: 名前 'self' が定義されていません。
-
[解決済み] Pythonで大きなファイルの行数を安価に取得する方法は?