最近在写一个程序涉及列表控件的大量数据刷新,使用了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次测试结果:
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次测试结果:
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次测试结果:
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次测试结果:
界面对比
总结 1、 直接向列表添加数据和绑定数据源两种方式的内存占用差距并不大; 2、 以直接向列表添加数据的方式,在数据量不大的情况下DataGridView占优,在大量数据时ListView的添加速度更快;但在实际使用中并不会频繁进行数据的添加,应该说这两种方式的差异不是很大; 3、 在使用DataGridView进行数据绑定后,若频繁地更新数据源,将会严重影响性能,原因应该是每次数据更新都会导致DataGridView发生重绘而降低性能,而当数据更新速度非常快时,甚至可能导致UI线程来不及绘制而发生错误; 4、 DataGridView的数据绑定适合大量数据的显示,而且这种方式也方便对数据进行修改,但不适合数据的频繁更新,故在数据频繁更新情况下,可采用重新绑定的方式,如上例4所示,首先开辟一个缓冲表,在一定量数据更新或者一定时间后重新绑定数据源,这样在性能上得到了明显的提升,远远好于其它三种方式,但缺点是牺牲了一定的内存空间; 5、 对于功能方面来说,DataGridView比ListView强大,不仅仅可以绑定各种数据源,还具有很多高级的功能,对于上面那种数据频繁更新的情况,可能有更好的解决方案,另外在界面方面,感觉ListView更美观些; |
|
来自: Cloud书屋 > 《DataGridView》