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

您基本上走在正确的轨道上,但我会避免调用 BeginInvoke 方法,直到您循环遍历数组中的进程以收集 TotalProcessorTime 时间值。

基本上,经验法则是尽可能少地在 UI 线程上花费时间——尽可能多地使用后台进程来完成工作。

另外,请确保线程池中没有线程或调度堆积。来自 Timer 类的 MSDN 文档:

如果 SynchronizingObject 属性是空引用(在 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 快得多,这非常慢。

这是它的入门教程:Virtual Mode ListView

另外,我今天早上才开始使用ObjectListView ,非常棒。

于 2012-06-21T19:11:00.013 回答