C++相談室 part136

レス数が950を超えています。1000を超えると書き込みができなくなります。
2018/06/07(木) 23:40:12.36ID:GNQuDMaA0
次スレを立てる時は本文の1行目に以下を追加して下さい。
!extend:on:vvvvv:1000:512

C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。

前スレ
C++相談室 part135
https://mevius.5ch.net/test/read.cgi/tech/1522495206/

このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.102【環境依存OK】
http://mevius.5ch.net/test/read.cgi/tech/1509780815/

■長いソースを貼るときはここへ。■
 http://codepad.org/
 https://ideone.com/

[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)

----- テンプレ ここまで -----
VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured
2018/07/09(月) 21:22:46.55ID:jdPfoelBa
メモリが大変な事になりそうなのでstringとint_to_floatの行のアドレスだけ取得して、
必要になった時に読みに行ってintからfloatに変換すれば?
2018/07/09(月) 21:26:46.46ID:AazuLIX60
floatの配列は別に用意して

struct LOG {
uint32_t str_start;
uint32_t str_end;
uint32_t str_line;
uint32_t num_start;
uint32_t num_end;
};

みたいな、
ブロックごとの構造体に入れていく方がいいのかな?
2018/07/09(月) 21:27:53.33ID:jdPfoelBa
vector<pair<size_t, size_t>> baka;//stringの開始位置とint_to_floatの開始位置をペアで管理。
2018/07/09(月) 21:29:34.68ID:AazuLIX60
適切なデータの持ち方はUIの全体表示の仕様次第と言うことになる
2018/07/09(月) 21:33:55.24ID:AazuLIX60
>>806に対して反応が無いから
数値情報が事前に必要なのかと思ったが
2018/07/09(月) 21:36:11.40ID:jdPfoelBa
あと気になったのはGUIに表示するのはstringの一行目?
2018/07/09(月) 21:43:08.83ID:AazuLIX60
1ブロック平均500行
1行平均30文字
でも100万ブロックある

全体画面で文字列は表示しないんじゃ?
2018/07/09(月) 21:58:36.33ID:lKzPjQ7Y0
初回DBに突っ込む
初回レコードのインデックスを作る
2018/07/09(月) 22:41:30.68ID:Xc+Rjkat0
最低限のパースを実施して各レコードのオフセットを配列に入れて必要になった時に解析して表示すればいいだけかと
2018/07/09(月) 22:43:45.27ID:AazuLIX60
同じ事を何度も書かなくて良い
2018/07/09(月) 22:49:34.81ID:tJIkM3K40
やっとおまえらもXMLが糞遅い理由を理解したか。
2018/07/09(月) 23:26:25.24ID:Kh8JJTJK0
>>776
構文的に難しくも無いのにわざわざ遅くする理由がわからん…
ていうかそもそもlexとかyacc使いでも滅多に使わん希ガス

今回の文字列処理の件はワッチョイ 0780-Rmg1の圧勝
2018/07/10(火) 00:11:54.08ID:L9+HOK/Ta
>>851
テストまでしていただいだきありがとうございます。
1分ちょっとならとてもいい感じです。
なるほどDRAMよりも高速なCPU内のキャッシュを有効に使うと効果的ってことですね。
そんなこと今まで考えたこともなかったです。勉強になります。

>>854
ご推察の通りです。

>>857
文字列の方はせいぜい10行〜20行です。
数値の方は何万行にもなったりします。

>>858
メモリは10GBつかっても問題にならないくらい潤沢に使えると思うので、まずは速度重視で行こうと思っています。

>>861,862
すみません昨日書き込みエラーになって書き込めなかったのでそのままでした。
クリックするたびに毎回int->float演算したら1項目で何万行もあったりするので
読み込み時に演算しておいた方がよいかなと思っていました。

>つづきます
2018/07/10(火) 00:20:12.97ID:L9+HOK/Ta
>>863
全部のフォーマットは複雑になってくるので簡易的なフォーマットをと思って出していましたが
説明していくと細かい話になってきましたのでもう少し具体的なものを書きます。
テストまでしてもらっているのに変わってすみません。。
-------------------------------
SECTION_NAME @
11200 11200 2 Jun 9 23:23:00 2018 A
This is pen. B
hello world. B
x 1 2 C
100 1 -2000 10
101 10 -2001 10
y 2 4
-100 10000
-101 10100
x 3 28
QQ subname -1 0 0 1 -21000000 600000 2 D
100 100 110 110
100 100 110 110
〜あと26行〜
SECTION_NAME E

@GUI表示する
A11200がx or yの個数、3カラム目がテキスト行の個数、それ以降は捨てる。11200のところは1の時もあれば100万超えることもある
BGUI表示する
Cこれが非常に多く、ひたすら繰り返される。x,yはランダムでくる。
1カラム目はx or y固定。x=次行に来る数値は4カラム。y=2カラム
2カラム目は1からインクリメントしていき、Aの11200回出てくる。カウント数値
3カラム目は次行から始まる数値行が何行かの数値
Dx or yの次の行にたまにこの行があります。この行も使いますが、ちょっと複雑なのでまずはスキップで。
Eここからまた@の繰り返し、要するにファイルの最後はCのところで終わる。
-------------------------------
2018/07/10(火) 00:23:35.36ID:L9+HOK/Ta
すみません、上記QQはQQという固定文字です。
行頭が"Q"のときはこの行という判定で良いと思います。

>>859,860
格納先は構造体に入れようと思っていて、下記のようにテキスト行も入れようかなと思っていました。

struct x_or_y{
 char type; // x or y
 int num; // Cの2カラム目
 float list;
};
struct elem{
 char section_name;
 char comments;
 array系の何かの型 x_or_y_array; // 配列にしておくと(Cの2カラム目-1)で簡単にアクセスできそう
};
2018/07/10(火) 01:34:56.63ID:C7bP6ErJ0
なんかのログなんだろうけど、ログ吐く時に読み込みやすいように出し方考え直した方がいいよ
大本が変えられないならパイプ繋いでフィルタ噛まして、読みやすいように直したファイルを並行して吐くとかさ

というかまず単にSECTION_NAMEごとにファイルぶった切っておくだけで良かったりしない?難しく考えすぎてない?
2018/07/10(火) 01:46:08.72ID:C7bP6ErJ0
どういうGUIが必要なのかわからんから的外れかもしれないけど
ワイならSECTION_NAMEごとに集計したHTMLファイルかなんかを出力するプログラムをワンパスかけてから
後でそのHTMLをブラウザで見ることを考えたくなるんだけどそれじゃダメなの?
2018/07/10(火) 06:48:34.57ID:wSs+8Os00
>>869
> 今回の文字列処理の件はワッチョイ 0780-Rmg1の圧勝

>>851の圧勝
>>851は0780-Rmg1みたいな遅いコードとは違う
2018/07/10(火) 06:50:09.17ID:wSs+8Os00
>>815の勝負はどちらも私の勝ち
2018/07/10(火) 06:58:28.74ID:wSs+8Os00
>>871
UIの表示内容はどういう感じを考えてる?
2018/07/10(火) 07:26:16.92ID:wSs+8Os00
A
1カラム目と2カラム目は同じ数字?
1カラム目がxの個数、2カラム目がyの個数?

C
y 2 4 の後、データ行が2行だけど4行の間違い?
データ行の値の範囲は?
2018/07/10(火) 07:29:57.69ID:U8fm2Of7a
section_nameは重複しますか?
2018/07/10(火) 07:31:15.21ID:wSs+8Os00
初めて開くファイルは使いやすいように変換して(キャッシュとして)保存しておいて
次回以降それを使うか
全ファイルバッチ処理で事前に変換しておくか

かな

ファイルを開く度に分オーダーかかるのは使いづらい
どちらが良いかは使い方次第で
2018/07/10(火) 07:49:59.14ID:wSs+8Os00
15GBオーダーのファイルがすでにいつくかあって
今後も増えるってことで良いんですよね?
2018/07/10(火) 07:55:16.04ID:wSs+8Os00
@の行は1ファイル何行くらい?
883754 (ワッチョイ 7ff1-XcsY)
垢版 |
2018/07/10(火) 14:27:03.15ID:VT/DQ/OS0
>>873,874
ソフトが出しているログなので変えられず、並行で吐くこともできないんです…

> ワイならSECTION_NAMEごとに集計したHTMLファイルかなんかを出力するプログラムをワンパスかけてから
これも考えたのですが、元ファイルと加工したファイルが常に等価ではないので、
間違って古いままの加工ファイルを参照する事故を、全員が気にする必要が
出てくるため今は保留とし、どうしてもできない時の最終手段と考えています。
こういうご意見も新しい視点が見えたりするんでありがたいです。

>>877
こんなのをイメージしています。
====================
項目名   | 個数 ※各カラムの説明行
====================
-SECTION1  | 11200
 subname1 | 8800 ※subnameがあれば折り畳みツリー形式。なければ折り畳みなし
 subname2 | 2400
+SECTION2  |  1
+SECTION3  | 666
====================
This is pen. ※SECTION1を選択するとそれに対応するテキストをここに表示
hello world.
====================
1 2 3 4 5 6 7 ※上と同じくSECTIONに対応した数値を特定できる番号を表示
8 9 10 11 12 13 14 ※ここはHTMLぽいものにし、数字クリックでその数値をprint
....
====================
884754 (ワッチョイ 7ff1-XcsY)
垢版 |
2018/07/10(火) 14:39:44.08ID:VT/DQ/OS0
>>878
> 1カラム目と2カラム目は同じ数字?
2カラム目が何の数字かまだ把握できていません。
とりあえず1カラム目と2カラム目の数値比較を行い、違う場合はエラーにしようと思います。
> y 2 4 の後、データ行が2行だけど4行の間違い?
ご指摘の通り4行の間違いでした。
> データ行の値の範囲は?
intの範囲を超えるか?ということですか?
int(-2147483648〜2147483647)で大丈夫と思います。

>>879
ユニークな名前で重複しません。

>>880
仰る通りどちらも一長一短で、今回は874さんに回答した通り、古いキャッシュを参照する事故を防ぐため、まずはテンポラリファイルを作らないことを考えています。

>>881
ファイルは毎回更新されて新しい15GBのファイル1つをインポートします。
15GBも現在のMAXサイズなのでそのうち20GBとかのものが出てくる可能性はありますが、
そこは「読み込みをひたすら待つ」と割り切りで考えています。

>>882
@の行→100行以下
Aの行→SECTIONごとに1行出るので同じく100行以下
Bの行→SECTIONごとにせいぜい20行程度。(20行*100行=20000行)
Cの行→SECTIONごとにたまに数千万のSECTIONあり(全SECTIONだと数千万〜億超えも出てきそう)
1つのSECTIONで数千万や億になり、それ以外のSECTIONは1000以下だったり、
1千万のSECTIONが複数SECTIONになることもあります。
そしてCに対して数値行が1行〜数十行、場合によっては数百行がくるので、Cとそれにかかる数値行が支配的になると思われます。

あと忘れていましたが、テキスト行は日本語がくることもあります。
それ以外は1byte文字です。
2018/07/10(火) 18:26:12.65ID:wSs+8Os00
キャッシュせず
変換して保存しないとなると
ほとんど読み込み時間
解析はそれに比べれば速い

なので
もし高速化したければ
全読みしない方法を考えるしか

全読みの時間くらいは待てるっていうならその方が簡単だけど

読み込み15GB 30秒って異様に速いな
うちの8TB 7200rpmのHDD(内側の方) だと78秒
SSD? RAID? キャッシュ? RAMディスク?
886754 (アウアウウー Sa0b-XcsY)
垢版 |
2018/07/10(火) 18:39:22.79ID:AbfeQ9t7a
>>885
HDDだと思います。
サーバ用なので高速なんですかね。
ちなみに cat /proc/cpuinfo でCPUも調べたらXeonで20コア以上ありました。
(ハイパースレッドかもしれませんが)
〜次キャッシュも民生用CPUより多いと予想されます。
2018/07/10(火) 22:05:54.09ID:zwgBQXGGa
>>885
あと、全読みの時間は >>851 を参考にすると2分くらいにはなりそうなので、それくらいなら全然待てます。
fgets, sscanfの時は5分かかっていて、それで我慢するしかないのか、と諦めかけていたので。

評価もscanfもしないでfgets()だけで78秒なんですかね?
大きな違いはCPU、CPU内臓キャッシュ、HDD、メモリあたりと思いますが、それだけで本当に半分以下になるのか少し気になりますね。
2018/07/10(火) 23:40:47.46ID:VT/DQ/OS0
とりあえずみなさんのコードを眺めましたが初めて目にする関数だらけで自分のレベルでは全くついていけてないです。
一つ一つの関数がどんな動作をするのか調べていきます。

>>782,833 を見るとcharのポインタをインクリして読むやりかたとか昔ちらっと読んだことある。程度のレベルなので。。

今833-837の動作確認ができたので、まずはこれがどう動いているかと、バイナリ読み込みの手法について調べていきます。
2018/07/11(水) 00:11:48.47ID:Faj75qU20
>>887
fgetsじゃなくて
freadで1MBずつ読むだけで78秒
庶民の普通のHDDはこんなもんです
解析入れてもほぼ同じなので
読むのに30秒なら解析入れても30秒で終わるよ
もちろんうまく作ればだけど
2018/07/11(水) 00:15:35.84ID:Faj75qU20
>>833をマネしたら30秒じゃ無理だろうけどね
2018/07/11(水) 09:43:08.56ID:zsyvWkTI0
ここはC++スレだからstd::regex使いなよ
>>833よりは速いし安全だぞ
2018/07/11(水) 12:53:48.19ID:MaErrZw3d
速いわけが無い
コードを書いて時間を測ってみなさい
2018/07/11(水) 12:58:55.32ID:zIxL2DqcM
脳高速
2018/07/11(水) 13:08:59.82ID:MaErrZw3d
sscanfが遅くてなんとかしたい
っていう話題なのに
DBだとかhtmlだとかregexだとか
頭がおかしいのが多いな
2018/07/11(水) 13:11:36.83ID:ElMeoT060
何度も表示させたいなら、解析結果をDBに格納しておくというのもいい方法だと思うが
事前にできるなら、見かけ上の実行時間も節約できるんだし
2018/07/11(水) 13:13:59.36ID:MaErrZw3d
ちょっとは要望を読んでから書けよ
2018/07/11(水) 13:31:20.08ID:jxunhcWG0
エアプ野郎が多いからねこのスレ
何の意味があるのかは知らんが
2018/07/11(水) 13:43:15.78ID:ElMeoT060
DBって要望がチャンと出てくる前の話だろう
サーバーで動かす位しか条件書いて無かったぞ
2018/07/11(水) 14:49:25.23ID:zsyvWkTI0
>>892
ループごとにregexオブジェクト作り直して時間測ってりゃ遅くなるわな
あれは使い回すもんだよやり直し
2018/07/11(水) 15:12:40.20ID:uU0OdRlq0
(ぴこーん!) boost::spiritだな!
2018/07/11(水) 15:20:28.24ID:jxunhcWG0
うん、regexよりはspirit::qiだよね
ワッチョイ a781-UVFsは的外れにも程がある
そしてそれ以前にregexもspiritもC++初心者に勧めるようなものではない
2018/07/11(水) 16:03:49.81ID:ElMeoT060
要件が全部出ていたわけじゃないのに
エスパーが登場して的当てたのか?そりゃスゴイな
2018/07/11(水) 21:40:55.60ID:Faj75qU20
>>743の時点で低レベルな記述が適していることくらいわかるだろ
15GBのテキストだぞ
2018/07/11(水) 21:42:08.49ID:Faj75qU20
>>899
>>894
2018/07/11(水) 22:32:29.61ID:DRc50H9L0
遅いから早くしたい
どんなに頑張っても無理なら
遅くてもよい仕組みにするという手もある
2018/07/11(水) 23:31:22.90ID:Faj75qU20
そういう事は頑張ってから言え
2018/07/11(水) 23:32:32.43ID:Faj75qU20
わざわざ遅い方法を選んで「無理」とか
ただの無能
908デフォルトの名無しさん (ワッチョイ 0780-Rmg1)
垢版 |
2018/07/11(水) 23:39:25.00ID:r1UJt2Dq0
やっぱりな低学歴しかいないわ
2018/07/11(水) 23:42:02.99ID:Faj75qU20
>>908
糞コードの負け犬君の登場ですね
910デフォルトの名無しさん (ワッチョイ 0780-Rmg1)
垢版 |
2018/07/11(水) 23:43:40.24ID:r1UJt2Dq0
そもそも最初のフォーマットと全然違うやんけ
普通にfgetsでとって、必要最低限の位置をマーキングするほうが
メモリに入れるのはそれだけ

位置からメモリブロックをとって、>>834>>835みたいなやりかたで表示が必要になったときに解析
911デフォルトの名無しさん (ワッチョイ 0780-Rmg1)
垢版 |
2018/07/11(水) 23:46:44.47ID:r1UJt2Dq0
そもそも解析アプリが出力してる規定されてるフォーマットなのに
いちいち形式をチェックする必要すらない

ホントな知恵遅れはなにをいってんのか意味不明だからな
クソニートのエアプログラマがテキトーなことばっかりいってんのは分かる
2018/07/11(水) 23:51:40.60ID:7/yJo8F80
スケジュールを開始するボタンに名前をつけたいけどいい名前が思い浮かばない
できれば6文字以内で
開始とか実行はダメ
2018/07/12(木) 00:02:21.07ID:1QTfgkTp0
>>912
とりあえずC++は関係ないな
914デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 00:09:52.26ID:LmT6lrwh0
ちなみな
fgets()は知恵遅れのキミラが考えてるよりぜんぜん速い
このスレの知恵遅れが書くようなクソコードより全然速い

書式付の標準関数は書式解析のオーバーヘッドがあるからクソ遅い
915デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 00:14:29.53ID:LmT6lrwh0
ちなみにな手で入力したときは
fscanfやsscanfは使えない
書式より引数が少ない場合簡単に死ぬからな

手で入力してるデータの場合fgets()でデータとって丹念に解析するしかない
つまりfscanfやsscanfの使用も想定する=間違いなく妥当な形式の入力がある
ことを意味する
2018/07/12(木) 00:15:24.91ID:KB59nVpm0
同じ事を何度も書かなくて良い
>>758

あとfgetsよりfreadの方が速い
当たり前ですが
917デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 00:17:19.69ID:LmT6lrwh0
メモリブロックとるときは
普通にfreadでいい
どうせ改行位置は解析しないといけないから
fgetsにやらせとけばいい

知恵遅れはTPOにあった関数の使い方がわかってないからな
918デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 00:22:11.12ID:LmT6lrwh0
知恵遅れはなにをどういった場面で使うのか分かってないからな
そもそも話がかみあうワケがない

知恵遅れにありがち
電車みて電車の型番いえるだけみたいな頭悪いのが
このスレにはウヨウヨいる
2018/07/12(木) 00:22:42.68ID:KB59nVpm0
わざわざ改行検索だけの為にメモリスキャン
ガチガチにチューニングするつもりならあり得ないですね
2018/07/12(木) 00:23:57.39ID:KB59nVpm0
適度なチューニングで妥協するんであれば
fgetsで良いかも知れませんが
2018/07/12(木) 00:28:02.27ID:KB59nVpm0
freadで読む時間とほぼ同じ時間で解析まで終わるので
中途半端な解析で止める必要もなくて
直接使いやすい形にすれば良い

あとは>>885
2018/07/12(木) 00:32:07.09ID:2mlSfrk0a
>>889

なるほどですね。
解析入れてもあまり変わらないのか。
scanfって本当に遅いんですね、嬉しい誤算です。

話題に出ているregexですが、↓ここを見た感じ、

ttps://www.sejuku.net/blog/25962

下記のように感じました。
perlやpythonの正規表現と似た感じなので使えるかもしれません。
1文字づつシフトしてスペースや改行を判定しながら抽出するより早いのであれば試して見ようと思います。

regcomp →正規表現オブジェクト?の作成。()でグループ化。読み込み前にすべてのフォーマットパターンを生成して使い回す。
regexec →正規表現オブジェクトを使ってパターンマッチ
rm_so、rm_eo →マッチの先頭、終端が取れるので文字列が拾える。こんな感じ?→strncpy(&str, data+match[i].rm_so, match[i].rm_eo - match[i].rm_so);
regfree →読み込み終了後にすべてのオブジェクトをこれで開放すればいい?

spirit::qiはググりましたがまったくわかりませんでした。。
2018/07/12(木) 00:34:07.21ID:KB59nVpm0
15GBともなると
関数を呼ぶ時間でもトータル時間に影響するんでね
fgetsの関数コール回数だってバカにならんでしょ

全てのfloatをvectorにpush_backするだけでも
結構な時間ですよ
この辺も工夫しないと
924デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 00:34:22.25ID:LmT6lrwh0
正規表現なんか使ったらコンパイル済の正規表現でも
クソ遅いにきまってるやんけ

そんなもん使うならスクリプトでやったほうがいい
925デフォルトの名無しさん (ワッチョイ b5b3-kMcx)
垢版 |
2018/07/12(木) 09:04:08.15ID:8O8kwVFO0
ディスク読むより遅いでしょうか。
2018/07/12(木) 09:40:21.55ID:yoYPGeS70
>>922
だからregexもspiritも使わなくていいってばw
すでに実例出してくれてるような昔ながらのC言語的な書き方でいいと思う
まともな実例も示さずに「○○使え」は無視していいよ
2018/07/12(木) 10:27:30.25ID:oZ8teohGM
頭使え
928デフォルトの名無しさん (ワッチョイ f1d2-LQig)
垢版 |
2018/07/12(木) 13:31:18.35ID:9k08EbFv0
ちなみに gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0 だと、 C++がちゃんとしてて、std::getline()はfread()と同じくらい速い。
各自で実際に試してみるとよいだろう。

Visual Studio だとstd::getline()はfgets()よりも遅い。
コンパイラによって性能に極端な差がでるのがC++のiostream周り。iostreamが地雷扱いされる主因。
2018/07/12(木) 14:27:06.99ID:Jbx8ub/k0
15GB なんて、もし画像ファイルなら、触った途端に、メモリ不足でフリーズするレベル。
普通、8GB ぐらいしか、メモリを積んでいないだろ

1行毎に、読んでは捨てる方式じゃないと無理。
それか、ファイル分割する

Ruby で、HTML, Node.js などが良さそう。
それか、DB
2018/07/12(木) 14:35:16.06ID:QybvZFcBd
順番にアホが書き込むスレ
2018/07/12(木) 14:43:21.06ID:QybvZFcBd
>>929
>>743から読んで出直してきなさい
2018/07/12(木) 20:53:29.39ID:KB59nVpm0
色々な言語で速度比較とか面白そう
2018/07/12(木) 21:42:21.02ID:KB59nVpm0
>>871のフォーマットでC++で作ったら
解析15GBで8.6秒
1バイト平均2クロック!

これを越えるには
マルチスレッド / AVX命令 /アセンブラ / GPU
に手を出さないと無理かな

----
Haswell
3.4GHz固定
シングルスレッド
C++で1文字ずつ15G文字解析
普通の命令のみ使用(SIMD命令は使用しない)
数値の合計のみ計算して結果を最後に表示
固定4KBを繰り返し解析、トータル15GB分の時間を計測
----
2018/07/12(木) 21:55:17.33ID:Ze/sD5Dv0
1ブロック内に数値が数万あってどうUIで表示すんのか気になる
2018/07/12(木) 22:00:17.37ID:KB59nVpm0
数値ならグラフにするとか画像にするとかフィルターを通してから間引くとか音声にして鳴らすとか
まあ色々とあると思う
2018/07/12(木) 22:08:43.66ID:8VUYfWV40
>>926
おとなしく1文字づつ評価します。

>>933
8.6秒早いですね。

自分はまず初バイナリ読み込みなので勉強から始めてとりあえず1行読みができましたが、
アスキー読み込みのfgetsの方が早かったです、、
コードを載せるのでどこが悪いか見てもらって良いですか?

対象=13GBのファイル(約8億行)。

○fgets版 →約17秒
if((fp=fopen(file_path,"r"))==NULL){
  printf("file not open %s\n", file_path);
 return 1;
}
while( fgets(buf,MAX,fp) != NULL ){
 buf;
}

次にバイナリ読み↓
2018/07/12(木) 22:11:04.95ID:8VUYfWV40
○バイナリ読み版 →約44秒
struct CCC {
 FILE *fp ;
 bool read(char* file_path);
 t_read_db read_db;
};
bool CCC::read(char file_path[]){
 FILE *fp;
 if((fp=fopen(file_path, "rb"))==NULL){ printf("ファイルを開けません。%s",file_path); return 0; }
 unsigned char buf[BUF_SIZE];
 int newline_index;
 while( !feof( fp ) ){
  size_t size = fread( &buf, sizeof(buf[0]), sizeof(buf), fp );
  // 終端処理。最大値で取得されてなければそこを末尾にする
  if( size != BUF_SIZE ) buf[size] = '\x00';
  // 取得bufの最後尾が改行でなければfpを改行まで戻す
  if( buf[size-1] != '\x0a' ){
   newline_index = -2;
   for(; buf[size+newline_index] != '\x0a'; --newline_index);
   fseek(fp,newline_index+1,SEEK_CUR);
   // bufの最後の改行の次にx00(null)を入れてそれ以降をカット
   // 「配列参照はポインタの移動より遅い」とあったがbufは実体で移動できないので[]参照で代入。
   buf[size+newline_index+1] = '\x00';
  }
  unsigned char const* c_buf = buf;
  while( c_buf[0] != '\x00' ){
   print_line(c_buf, &c_buf);
  }
 }
}
2018/07/12(木) 22:11:35.38ID:8VUYfWV40
bool print_line(unsigned char const* p_buf, unsigned char const** pct_next);
bool print_line(unsigned char const* p_buf, unsigned char const** pct_next){
 unsigned char const* c_buf = p_buf;
 //改行位置を検索
 for(; *c_buf != '\x0a'; ++c_buf);

 char line[LINE_SIZE];
 strncpy( line, (char const*)p_buf, c_buf - p_buf );
 // nullで区切らないと過去に代入した文字数より少ないときにゴミが残る
 line[c_buf - p_buf] = '\x00';

 ++c_buf;
 *pct_next = c_buf;
 return true;
};
2018/07/12(木) 22:13:44.64ID:8VUYfWV40
○fgets版 →約17秒
○バイナリ読み版 →約44秒

両方ともとりあえず文字列の読み取りまでしていて、条件は同じではないかと思うのですが、freadのほうが倍以上遅いです。。
2018/07/12(木) 22:14:27.55ID:oZ8teohGM
>>936
setvbufはしないの?
2018/07/12(木) 22:15:24.64ID:Ze/sD5Dv0
>>935
fgetsで悩んでる人がそのハードル超えることできるか心配してるんですよ
2018/07/12(木) 22:17:52.40ID:8VUYfWV40
すみません、44秒はfreadの読み込みサイズ(BUF_SIZE)が512byteでした。
16MBにすると34秒になりましたが、それでも倍の差があります。
2018/07/12(木) 22:33:29.40ID:oZ8teohGM
>>942
mmapがいるかなぁ
BSD grep のソースのコメントにこの辺りの高速化の
コツが書いてあるので一読されたし
2018/07/12(木) 23:04:55.64ID:8VUYfWV40
>>943
mmapですか。
要チェックですかね。
でもそれだけで数倍早くなるとも思えないし、 >>933 さんの8.6秒は圧倒的パフォーマンスですね。
シングルスレッドで特殊なものは使ってないようだし、たった4KBの繰り返しだし。
根本的なところから違いそう。。

>>933
もし可能であれば、テストしたコードを見せていただくことはできませんでしょうか?
945デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 23:10:07.38ID:LmT6lrwh0
あのな
そこまで読みこみ速度を気にするなら
そもそもFILEポインタ使う関数なんか使うなよ
そもそもFILEポインタ使う関数はバッファリングしてるから
いちいちメモリコピーしてんのに

そこまでガタガタいうなら
openとreadで普通にメモリブロック読みこむ処理にしろよ
ハゲ
2018/07/12(木) 23:13:14.06ID:8VUYfWV40
>>940,941
setvbufも初耳です。
941さんのコメントからすると、これまた難しそう。。

色々と情報ありがとうございます。
947デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 23:13:42.35ID:LmT6lrwh0
ちなみになFILEポインタは構造体にファイルデスクリプタもってる
fopenでopenを呼び出してファイルディスクリプタ生成して構造体に保存してる
ファイル読むときはファイルディスクリプタでread使ってバッファリングしながら読みこんでる

このスレの低学歴どもはこういう基本的なことわかってんの
948デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 23:15:00.75ID:LmT6lrwh0
そのsetvbufというのが
バッファリングするバッファのサイズだ
つまり、バッファにたまったメモリをひたすらコピーしてる
2018/07/12(木) 23:15:52.81ID:oZ8teohGM
filenoとfdopenの理解はデフォ
950デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 23:18:11.64ID:LmT6lrwh0
32bit越えるmmapとか
そんなやばそうなもん使うのか
まずちゃんと動作するか確認することになるわ
951デフォルトの名無しさん (ワッチョイ a580-lT5f)
垢版 |
2018/07/12(木) 23:31:34.69ID:LmT6lrwh0
休日にオレのエレガントなファイル読みこみ処理作ってやるから
楽しみにしてなさい
2018/07/12(木) 23:40:59.34ID:KB59nVpm0
HDDの一番外側15GB
セクタ直読みで60.1秒
平均 250MB/s でした

7200rpmの8TBのHDDです
2018/07/12(木) 23:44:58.13ID:KB59nVpm0
>>851の77.9秒はHDDの内側の方でfreadでの読み込み
どちらもHDDの限界と思います
2018/07/12(木) 23:49:15.37ID:KB59nVpm0
>>944
解析時間のほとんどが>>782のようなコードです
ちょっと変えましたが
2018/07/12(木) 23:53:49.46ID:KB59nVpm0
改行を探す為だけにスキャンする必要はありませんし、コピーする必要もありません

ほとんどをしめる数値の行は
>>782の処理で区切りまでポインタが進みます
2018/07/13(金) 00:20:28.77ID:Zia1PITL0
>>951
ありがとうございます。楽しみにしています。

>>933,952,953
解析と読み込みを分けているんですね、8.6秒は解析で、読み込みがHDDのハード限界の60秒(高速な外側)、77.9秒(低速な内側)。
そこで >>851 の読み込み、解析合わせると78.1秒でほとんどがHDD律速ということか。

>>954,955
ご説明ありがとうございます。 >>782 の動作を調べてみます。
freadの扱いで質問なのですが、byte単位で取得すると最後尾が改行ではなく途中で終わることがあるので、
改行区切りになっているdata変数がだと思って、937に書いたコードでは、自分がわかる知識で考えて、
freadで読み込んだあとに改行のところまでfseekで戻しているんですが、この考え方はあっているのでしょうか?
2018/07/13(金) 00:21:42.58ID:Zia1PITL0
data変数がだと思って →×
data変数が必要だと思って →○
レス数が950を超えています。1000を超えると書き込みができなくなります。
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況