リストビューの表示を高速化するには?

解決


カナガワ  2004-09-18 08:57:38  No: 54525

リストビューの表示を高速化する方法について教えてください。

大量(最大1万件)のデータをリストビューに表示させるのですが、一番下のアイテムを選択表示させデータの流れる様子を、画面に表示させたいのです。

SetRedrawを用いてInsertItemを行っています。1万件を超えるとDeleteItemを用いて先頭のアイテムを削除しています。現在表示速度が遅いのかデータが溜まっています。さらに画面がちらついてしまいます。

画面のちらつきはOnEraseBkgndを用いて、描画を省いているのですが上手く画面のちらつきがおさまりません。

良い方があればご教授お願いいたします。


シャノン  2004-09-18 22:46:04  No: 54526

仮想リストビューを使ってみるとよろしいかと。
今だと、メモリ使用量も結構デカいと思います。
仮想化すると、メモリ使用量は数分の一、表示速度は数倍以上に跳ね上がりますよ。
ソートなんかも全部自分で面倒見てやらなきゃなりませんけど。

仮想リストビューってサンプル少ないんですよね…
このへんでどうでしょう?

http://www.codeproject.com/listctrl/virtuallist.asp


カナガワ  2004-09-21 07:49:17  No: 54527

ご回答ありがとうございます。

仮想リストビューを使うと断然早くなりました。
すいませんが、ここでもう一つ質問です。

現在、CListにAddTailしたデータをSetItemCountExとEnsureVisibleにより
仮想リストビューを使ってOnGetDispInfoにて表示しています。
10000件を超えた際はCListに積んだデータをRemoveHeadしていますが、
10000件を超えると、明らかに遅くなってしまいます。

10000件積む前の処理との違いは、RemoveHeadと画面に更新を掛けるために
リストをRedrawWindowさせているだけなんですが、ここまで遅くなる
ものなのでしょうか?


シャノン  2004-09-21 19:41:57  No: 54528

CList ってことは、GetDispInfo でアイテム情報を求められたときに
目的の位置まで延々辿って探しに行ってるのが遅いんじゃないかな、と
思ってみたりします。

RemoveHead が遅かったらリスト構造の意義が無いし
再描画が遅かったら仮想リストビューの意義が無いでしょうから。

後で時間があるときに試してみたいと思います。


たく  2004-09-21 19:53:04  No: 54529

以前同様の問題を抱えていました。
回答にはならないかもしれませんが
そのときの調査と対応のメモを書きます。

・選定したコンテナは適切か?
  挿入・削除はリストのどの部分で発生するか
  仮想リストビューはランダムアクセスできないコンテナでは効率が落ちる
  → CArrayを使用していたが、STLのdequeを採用した。

・選定したソート方法は適切か?
  リストの更新時、ソート処理に負荷がかかっているようだ
  → 各種ソートを比較しstable_sortを採用

・冗長な処理はないか?
  一回のデータ受信の挿入・削除それぞれでソート処理をしている。
  → ソートのタイミングを変更
  受信間隔でデータ更新処理が終わらない。
  → 処理中にデータを受信した場合は処理をスキップした。
  (どちらにしろ表示されないため)

私が改修担当したのは、イメージを持つツリー形状のリストビューでしたので、直接参考にはならないかもしれませんがとりあえず書いておきます。


カナガワ  2004-09-29 08:38:54  No: 54530

シャノン様、たく様貴重なご意見ありがとうございました。

お二人の意見を参考にいろいろ試してみました。その結果をご報告します。
・選定したコンテナは適切か?
挿入はリストの最後尾、削除は先頭で起こります。現在作成しているものはソート、検索をする必要が無いため、ランダムアクセスする必要が無いと判断しました。そこでCArrayを用い、リングバッファを作成し、削除の処理を省きました。
(すいません、コンテナがよくわかりません。)

・選定したソート方法は適切か?
ソートの必要はありません。

・冗長な処理はないか?
受信中に、余分な処理を削除しました。受信間隔でデータ更新処理(CArrayにデータを積むだけ)は終わっています。
(いまさらで申し訳ありませんが、ちなみに受信間隔は2msecです。)

いろいろ試行錯誤したのですが、私の結論としましては再描画に時間がかかっているのかと思いました。それというのも、

GetDispInfoではCArrayからデータを加工して表示するようにしていました。そこでDEBUGとして直値を表示してすぐ処理を返すようにしてみたのですが、それでもCPU使用率が100%まで上がってしまいます。

1万件に達するまでは仮想リストビューによりSetItemCountExを用い1行表示して、1行分スクロールさせている為、CPU使用率が跳ね上がることがありません。1万件に達した時はリングバッファ上では先頭データに追加、仮想リストビュー上では先頭データの削除、最後尾にデータ追加なのでRedrawItemsを用い、画面に表示されているリストを再描画させています。その為、画面に表示されている分を描画させる時間がかかっているのだと判断しました。(実際にCPU使用率は、1万件に達するまでのCPU使用率に画面に表示されているデータ数分掛け算したぐらいでした。)
再描画によりCPU使用率が上がり、その間もデータを受信しているため、1万件を超えると、データが溜まっているのだと思います。

今回の対応方法としまして、Timerを用い更新周期で描画するようにしました。この対応により、CPU使用率が跳ね上がることもなく、受信も溜まらなくなりました。

まだまだわからないことが多く、毎日勉強です。今回は一応上記の対応を取りましたが、もしよろしければ今後の勉強の為、私の取った方法についてお二人の意見をお聞かせください。

いろいろありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加