ListView和DataGridView性能比较

最近在写一个程序涉及列表控件的大量数据刷新,使用了ListView控件,但觉得逐条向ListView添加数据的方式性能不是很高,想改为数据绑定方式,网上搜索半天发现ListView不支持数据绑定,作罢,索性测试下ListView和DataGridView的性能。

性能测试静态类(负责测试耗时和内存占用)

    public static class PerformanceMonitor

    {

        private static Stopwatch sw = new Stopwatch();

        private static float duration = 0;

        public static void StopwatchStart()

        {

            sw.Start();

        }

        public static void StopwatchStop()

        {

            sw.Stop();

            duration = (float)sw.Elapsed.TotalSeconds;

        }

        public static void PrintStopwatchDuration()

        {

            Console.WriteLine(string.Format("耗时:{0}s", duration.ToString()));

        }

        public static double GetProcessUsedMemory()

        {

            double usedMemory = 0;

            usedMemory = Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0;

            Console.WriteLine(string.Format("内存占用:{0}M", usedMemory.ToString()));

            return usedMemory;

        }

    }

消息产生类(负责产生指定个数的消息)

    public class Generator

    {

        private Thread generateMessageThread;//消息产生线程

        private int count;//消息数目

        public delegate void GenerateOneMessageEventHandler(string message);

        public event GenerateOneMessageEventHandler GenerateOneMessageEvent;

        public Generator()

        {

            count = 0;

        }

        public void StartGenerate(int num)

        {

            //产生num条消息

            count = num;

            generateMessageThread = new Thread(new ThreadStart(GenerateMessage));

             generateMessageThread.IsBackground = true;

             generateMessageThread.Start();

        }

        private void GenerateMessage()

        {

            PerformanceMonitor.StopwatchStart();//开始计时

            string message = string.Empty;

             for (int i = 0; i < count; i++)

            {

                message = "One Message";

                 if (GenerateOneMessageEvent != null)

                {

                    GenerateOneMessageEvent(message);

                }

            }

            PerformanceMonitor.StopwatchStop();//结束计时

            PerformanceMonitor.PrintStopwatchDuration();//打印耗时

            PerformanceMonitor.GetProcessUsedMemory();//打印内存占用

        }

    }

ListView控件逐条添加方式 Form类:

    public partial class FormListView : Form

    {

        private int sequenceNumber;//列表序号

         private ListViewItem lvi;//列表项

        Generator messageGenerator1;//消息产生类,由事件触发列表的更新

        private delegate void AppendMessageDelegate(string message);

        public FormListView()

        {

            InitializeComponent();

             listView.Columns.Add("序号");

             listView.Columns.Add("消息");

             sequenceNumber = 0;

            messageGenerator1 = new Generator();

            messageGenerator1.GenerateOneMessageEvent += new Generator.GenerateOneMessageEventHandler(AppendOneMessageToListView);

            messageGenerator1.StartGenerate(1000);

        }

        public void AppendOneMessageToListView(string message)

        {

            if (listView.InvokeRequired)

            {

                AppendMessageDelegate del = new AppendMessageDelegate(AppendOneMessageToListView);

                listView.Invoke(del, message);

                return;

            }

            sequenceNumber++;

             lvi = new ListViewItem(sequenceNumber.ToString());

             lvi.SubItems.Add(message);

             listView.Items.Add(lvi);

        }

    }

5次测试结果:

  10条 100条 1000条 10000条 10000
耗时(S) < 0.1 < 0.5 3 30 380
内存占用(M) 23.04296875 23.43359375 24.52734375 29.71875 79.73

DataGridView逐条添加方式 Form类:

    public partial class FormDataGridView : Form

    {

        private int sequenceNumber;//列表序号

        Generator messageGenerator2;//消息产生类,由事件触发列表的更新

        private delegate void AppendMessageDelegate(string message);

        public FormDataGridView()

        {

            InitializeComponent();

            dataGridView.Columns.Add("序号", "序号");

             dataGridView.Columns.Add("消息", "消息");

             messageGenerator2 = new Generator();

            messageGenerator2.GenerateOneMessageEvent += new

Generator.GenerateOneMessageEventHandler(AppendOneMessageToDataGridView);

            messageGenerator2.StartGenerate(1000);

        }

        public void AppendOneMessageToDataGridView(string message)

        {

            if (dataGridView.InvokeRequired)

            {

                AppendMessageDelegate del = new AppendMessageDelegate(AppendOneMessageToDataGridView);

                dataGridView.Invoke(del, message);

                return;

            }

            sequenceNumber++;

             dataGridView.Rows.Add(new object[] { sequenceNumber, message });

        }

    }

5次测试结果:

  10条 100条 1000条 10000条  
耗时(S) < 0.1 < 0.3 1.3 17  
内存占用(M) 23.6328125 24.3203125 24.91796875 30.140625  

DataGridView数据绑定方式(只负责绑定) Form类:

    public partial class FormDataGridView : Form

    {

        private int sequenceNumber;//列表序号

         private DataTable messageTable;

        Generator messageGenerator3;

        public FormDataGridView()

        {

            InitializeComponent();

            messageGenerator3 = new Generator3();

            messageGenerator3.GenerateOneMessageEvent += new

Generator.GenerateOneMessageEventHandler(AppendOneMessageToDataTable);

            messageTable = new DataTable();

             messageTable.Columns.Add("序号");

             messageTable.Columns.Add("消息");

             dataGridView.DataSource = messageTable;

             messageGenerator3.StartGenerate(1000);

        }

        private void AppendOneMessageToDataTable(string message)

        {

            sequenceNumber++;

             messageTable.Rows.Add(new object[] { sequenceNumber, message });

        }

    }

5次测试结果:

  10条 100条 1000条 10000条
耗时(S) < 0.01 0.7 5 56
内存占用(M) 23.3359375 25.87890625 26.359375 32.3671875

DataGridView数据绑定方式(定量/定时重绑定) Form类:

    public partial class FormDataGridView : Form

    {

        private int sequenceNumber;//列表序号

         private DataTable messageTable;

         private DataTable messageTableBuffer;

        Generator messageGenerator4;

        private delegate void ChangeDataSourceDelegate();

        public FormDataGridView()

        {

            InitializeComponent();

            messageGenerator4 = new Generator3();

            messageGenerator4.GenerateOneMessageEvent += new

Generator.GenerateOneMessageEventHandler(AppendOneMessageToDataTable);

            messageTable = new DataTable();

             messageTableBuffer = new DataTable();

             messageTable.Columns.Add("序号");

             messageTable.Columns.Add("消息");

             messageGenerator3.StartGenerate(10000);

        }

        private void AppendOneMessageToDataTable(string message)

        {

            sequenceNumber++;

             lock (messageTable)

            {

                messageTable.Rows.Add(new object[] { sequenceNumber, message });

                 if (sequenceNumber % 1000 == 0)

                {

                    //1000条数据重绑定

                    ChangeDataSource();

                }

            }

        }

        public void ChangeDataSource()

        {

            if (dataGridView.InvokeRequired)

            {

                ChangeDataSourceDelegate del = new ChangeDataSourceDelegate(ChangeDataSource);

                dataGridView.Invoke(del);

                return;

            }

            dataGridView.DataSource = null;//解绑定

             messageTableBuffer.Merge(messageTable.Copy());//将messageTable数据添加至messageTableBuffer

             messageTable.Clear();//清除messageTable

            dataGridView.DataSource = messageTableBuffer;//重绑定

        }

    }

3次测试结果:

  1000条 10000条 100000条
耗时(S) < 0.1 0.6 16
内存占用(M) 24.5078125 33.1484375 73.05859375

界面对比

总结

1、   直接向列表添加数据和绑定数据源两种方式的内存占用差距并不大;

2、   以直接向列表添加数据的方式,在数据量不大的情况下DataGridView占优,在大量数据时ListView的添加速度更快;但在实际使用中并不会频繁进行数据的添加,应该说这两种方式的差异不是很大;

3、   在使用DataGridView进行数据绑定后,若频繁地更新数据源,将会严重影响性能,原因应该是每次数据更新都会导致DataGridView发生重绘而降低性能,而当数据更新速度非常快时,甚至可能导致UI线程来不及绘制而发生错误;

4、   DataGridView的数据绑定适合大量数据的显示,而且这种方式也方便对数据进行修改,但不适合数据的频繁更新,故在数据频繁更新情况下,可采用重新绑定的方式,如上例4所示,首先开辟一个缓冲表,在一定量数据更新或者一定时间后重新绑定数据源,这样在性能上得到了明显的提升,远远好于其它三种方式,但缺点是牺牲了一定的内存空间;

5、   对于功能方面来说,DataGridView比ListView强大,不仅仅可以绑定各种数据源,还具有很多高级的功能,对于上面那种数据频繁更新的情况,可能有更好的解决方案,另外在界面方面,感觉ListView更美观些;

weinxin
我的微信
一个码农、工程狮、集能量和智慧于一身的、DIY高手、小伙伴er很多的、80后奶爸。
Igor
  • 版权声明: 发表于 2019-12-1612:06:56
  • 转载注明:http://blog.tsingmac.com/prolions/codelanguage/mscs/2240/
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: