0

私は C# と .NET プログラミングが初めてで、Windows TaskManager のような Windows フォーム アプリケーションを開発しようとしています。最初に、System.Diagnostics.Process から収集した情報を使用して listView にデータを入力します。次に、リストビュー データを毎秒更新しようとする MethodInvoker デリゲートを使用して System.Threading.Timer を開始します。

問題は、アプリケーションが非常に遅いことです。そして、確かに、私は愚かなことをしています。


public partial class Form1 : Form
    {
        private System.Threading.Timer t;
        private Process[] procVett;

        public Form1()
        {
            InitializeComponent();



        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.loadAppInfo(null);
            TimerCallback timerDelegate = new TimerCallback(this.refresh);
            this.t = new System.Threading.Timer(timerDelegate, null, 1000, 3000);
        }


        private void refresh(Object stateInfo)
        {
            procVett = Process.GetProcesses();

            this.BeginInvoke( (MethodInvoker)delegate
            {
                ListView.ListViewItemCollection ic = this.appList.Items;
                ListView.ListViewItemCollection procIc = this.procList.Items;
                time.Text = DateTime.Now.ToLongTimeString();
                int count = 0;
                procList.BeginUpdate();

                foreach (Process p in procVett)
                {

                    try
                    {
                        string cputime = p.TotalProcessorTime.TotalMinutes.ToString();

                        procIc[count].SubItems[1].Text = ("");
                        procIc[count].SubItems[2].Text = (cputime);
                        procIc[count].SubItems[3].Text =(p.WorkingSet64.ToString());
                        procIc[count].SubItems[4].Text = ("");

                    }
                    catch (System.Exception)
                    {

                    }

                    count++;
                }
                procList.EndUpdate();

            }, null);

        }
}
4

3 に答える 3

2

あなたは基本的に正しい軌道に乗っていますが、配列内のプロセスをループして TotalProcessorTime 時間値を収集するまで、BeginInvoke メソッドの呼び出しは避けます。

基本的に、経験則として、UI スレッドに費やす時間はできるだけ少なくすることです。バックグラウンド プロセスを使用してできるだけ多くの作業を行います。

また、スレッドプールにスレッドやディスパッチが積み重なっていないことを確認してください。Timer クラスの MSDN ドキュメントから:

SynchronizingObject プロパティが null 参照 (Visual Basic では Nothing) の場合、ThreadPool スレッドで Elapsed イベントが発生します。Elapsed イベントの処理が Interval より長く続く場合、イベントは別の ThreadPool スレッドで再び発生する可能性があります。この場合、イベント ハンドラーは再入可能にする必要があります。

そのため、再入可能性に注意し、再入可能タイマー イベントを無視するか、古いスレッドでの処理を強制終了します (スレッド セーフなシグナル メカニズムを使用します)。

于 2012-06-21T18:32:47.640 に答える
1

私がコメントで言ったこととは別に:

ListViewItems の個別のコレクションを作成し、プロセス情報を別のスレッド ( BackgroundWorkerまたは単に別のスレッド) で解析し、そのコレクションを更新後に ListView で使用すると、現在表示されているリストは表示されません。凍った。

于 2012-06-21T18:10:50.467 に答える
0

現在表示されているアイテムのみを表示する ListView で VirtualMode を使用することをお勧めします。1,000,000 個のアイテムがあり、#1,000-1020 しか描画していない場合、それらを要求し、メモリ内のアイテム リストからそれらを取得する方法を指定すると、それらが描画されます。

信じられないほど遅い ListViewItems を自分で追加するよりもはるかに高速です。

そのためのスターター チュートリアルは次のとおりです:仮想モード ListView

また、今朝ObjectListViewを使い始めたばかりですが、すばらしいです。

于 2012-06-21T19:11:00.013 に答える