HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2021
0110
あっすんテキストの書き込み速度について2解決


あっすん

リンク

2021/1/10(Sun) 21:57:09|NO.92040

1行だいたい150文字程度で行数が平均で5000行、多い時は最高で60000行くらいになる
テキストデータの先頭から1行づつ読み込んで処理を加えて同データに上書き、
または別バッファに先頭から追加していく、と言う処理について質問なのですが、

最初は実験でnoteget命令で1行読み込んで読み込んだその1行を元のデータにnoteadd命令で
上書きと言う具合でやってみたのですが処理がとても遅かったので検索をしまして
http://www.hspcenter.com/hsptvm/archives/2007/03/hsp3_17.html
上記URLを参考にgetstr命令を使用して1行づつ読み込んだらとても早くて良かったのですが
読み込んだ1行に処理を加えたあと、同バッファへnoteadd命令で上書き、または
別バッファへ先頭から追加していく処理がどちらも相変わらず遅くて困っています。
何か早くなる方法がありますでしょうか?
ちなみに参考にしているソフトですと大体5000行くらいですと2、3秒程度で全ての処理が
終わってしまいます。そこまで早くなくともできれば今よりは早くなれば助かります。


loop_cnt = 5000 sdim text,10000 // 簡易的に5000行のテキストデータ作成 repeat loop_cnt text = text + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" title "" + cnt await loop button "実行!",*gogo stop *gogo sdim aaa,10000 repeat getstr data,text,index,0 ; 1行づつ取り出す index=index+strsize ; 次の取り出し位置に移動 if strsize=0 : break ; サイズが0ならば終了 aaa = aaa + "--" + data + "\n" ; 処理施してaaaバッファへ追加書き込み title "" + cnt await loop mes "終了" stop



この記事に返信する


ベイン

リンク

2021/1/10(Sun) 23:25:14|NO.92041

結論からいうと次のようにやると高速にできます。
(これは「簡易的に5000行のテキストデータ作成」の部分ですが、*gogo の方も同様です。)


loop_cnt = 5000 sdim text, 10000 text_len = 0 ; text の長さ repeat loop_cnt ; text に追加する文字列 new_line = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" new_line_len = strlen(new_line) ; poke 命令で変数のサイズを超えて書き込むとエラーになるので、変数の領域を拡張する。 if text_len + new_line_len >= varsize(text) { memexpand text, (text_len + new_line_len + 1) * 2 } ; text の末尾に文字列を書き込む。 poke text, text_len, new_line text_len += new_line_len loop ; 念のため 5000 行書かれたことを確認 notesel text mes notemax

----

解説:

文字列を書き込む先の変数 text に加えて、
それの長さを覚えておくための変数 text_len を追加します。
常に strlen(text) == text_len が成り立つようにしておくことで、
strlen(text) の計算を省略するためです。
text を変更する際は text_len も同時に変更する必要があるので、注意してください。


sdim text, 10000 text_len = 0 ; text の長さ

次に、text に文字列を追記するときの処理です。
追記する文字列の長さを何度か使うので、変数 (new_line_len) に入れています。


; text に追加する文字列 new_line = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n" new_line_len = strlen(new_line)

後で poke 命令を使うのですが、これは変数のメモリを自動では拡張しないので、
追記した文字列が text の残りのメモリに収まらないとエラーになってしまいます。
そのため、 memexpand 命令を使って text のメモリを拡張します。
ここでは、文字列を追記した後に必要な大きさ (text_len + new_line_len + 1) がメモリサイズを超える場合は、
変数のメモリをその2倍の大きさまで拡張しています。(詳細は後述)


; poke 命令で変数のサイズを超えて書き込むとエラーになるので、変数の領域を拡張する。 if text_len + new_line_len >= varsize(text) { memexpand text, (text_len + new_line_len + 1) * 2 }

最後に poke 命令を使って、text の末尾に文字列を書き込みます。
先ほど書いたように text_len も変更が必要です。


; text の末尾に文字列を書き込む。 poke text, text_len, new_line text_len += new_line_len

なぜこれが速いか:

noteadd 命令は文字列の末尾を探すために strlen(text) に相当する計算を行っているのですが、
これは text の長さに比例して時間がかかるので、文字列が長くなってくると遅いです。
poke は書き込む位置をパラメータで直接指定できるので、この計算を省略できる、というのが理由です。

----

memexpand のメモリの計算式について:

memexpand 命令自体は、文字列全体をコピーする可能性があるので時間がかかります。
変数のメモリをぴったりにしてしまうと、ループのたびに memexpand が実行されることになり、
全体としてかなり時間がかかります。
ここではメモリを倍々に拡張していくことで memexpand が必要になる機会を少なくしています。

----

詳細は以下の記事も参照:

[HSP3 文字列のひみつ](https://www.onionsoft.net/hsp/v36/doclib/hsp3str.htm)
[文字列の扱い](http://prograpark.ninja-web.net/HSP/other/proc_string.html)



あっすん

リンク

2021/1/12(Tue) 11:29:05|NO.92047

ベイン様
返信ありがとうございます!
教えて頂いたスクリプトを参考に今製作しているプログラムに組み込んだ所、
約60000行のテキストファイルも数秒で処理する事ができてあまりの速さに驚いております!!
教えて頂いて本当にありがとうございました!



ONION software Copyright 1997-2021(c) All rights reserved.