首页 > 代码库 > 转载:数据的加载性能比较

转载:数据的加载性能比较

使用Listview等控件加载数据时,第一时间想到的就是ObservableCollection,这个东西蛮好,如果新增、删除、修改数据,都会自动更新UI。

可是,如果不需要增删改,显示大数据量,这个东西的加载性能怎么样呢?

做个实验。

1.准备数据,在本地磁盘上创建20000个文件,将其加载到ListView中。

技术分享
  var testPath = @"D:\TestLargeData\Test10000";            if (!Directory.Exists(testPath))                Directory.CreateDirectory(testPath);            else            {                MessageBox.Show("test file has been created");                return;            }            for (int i = 0; i < 20000; i++)                File.Create(Path.Combine(testPath, Path.GetRandomFileName()));

2. 使用ObserableCollection加载

技术分享
    #region data source 1        /// <summary>        /// files and directories in current directory, display in listview        /// </summary>        ObservableCollection<FileItem> allFiles1 = new ObservableCollection<FileItem>();        /// <summary>        ///  files and directories in current directory, display in listview        /// </summary>        public ObservableCollection<FileItem> AllFiles1        {            get { return allFiles1; }            set            {                if (allFiles1 != value)                    allFiles1 = value;                NotifyPropertyChanged("AllFiles1");            }        }        #endregion        #region load data method---1        /// <summary>        /// when current directory path change ,refresh listview        /// </summary>        public void Refresh1()        {            LoadLastFiles();        }        /// <summary>        /// loading last file task         /// </summary>        void LoadLastFiles()        {            var files = Directory.EnumerateFileSystemEntries(testPath);                      DateTime dtBegin = DateTime.Now;            LogHelper.Log("1====loading begin:");            foreach (var pageFile in files)            {                Invoke(delegate                {                    allFiles1.Add(GetFileItem(pageFile));                });            }            LogHelper.Log("1====loading ok:" + (DateTime.Now - dtBegin).TotalSeconds);            LogHelper.Log("1====current ItemsCount:" + allFiles1.Count.ToString());        }        #endregion

3.使用List加载

技术分享
        #region datasource 2        /// <summary>        /// files and directories in current directory, display in listview        /// </summary>        List<FileItem> allFiles2 = new List<FileItem>();        /// <summary>        ///  files and directories in current directory, display in listview        /// </summary>        public List<FileItem> AllFiles2        {            get { return allFiles2; }            set            {                if (allFiles2 != value)                    allFiles2 = value;                NotifyPropertyChanged("AllFiles2");            }        }        #endregion        #region load data method---2        /// <summary>        /// when current directory path change ,refresh listview        /// </summary>        public void Refresh2()        {            LoadLastFiles2();        }        /// <summary>        /// loading last file task         /// </summary>        void LoadLastFiles2()        {            var files = Directory.EnumerateFileSystemEntries(testPath);            AllFiles2 = new List<FileItem>();            DateTime dtBegin = DateTime.Now;            DateTime dtLastRefresh = DateTime.Now;            LogHelper.Log("2====loading begin:");            foreach (string file in files)            {                AllFiles2.Add(GetFileItem(file));                NotifyPropertyChanged("AllFiles2");            }            LogHelper.Log("2====loading ok:" + (DateTime.Now - dtBegin).TotalSeconds);            LogHelper.Log("2====current ItemsCount:" + AllFiles2.Count.ToString());        }        #endregion

这次对比的结果是 :

04:23:13 235 | 1====loading begin:

04:23:13 850 | 1====loading ok:0.615

04:23:13 851 | 1====current ItemsCount:73338

04:23:15 458 | 2====loading begin:

04:23:15 961 | 2====loading ok:0.503

04:23:15 962 | 2====current ItemsCount:73338

对比发现,两个差别不大的。

4. 上面的实验,数据是在主线程加载的,实际的数据加载一般都是利用线程加载的,所以修改代码如下:

5. ObserableCollection 加载放在线程中,需要Invoke了,如下:

技术分享
        #region load data method---1        /// <summary>        /// when current directory path change ,refresh listview        /// </summary>        public void Refresh1()        {            //LoadLastFiles();            allFiles1.Clear();            Thread thread1 = new Thread(new ThreadStart(LoadLastFiles));            thread1.Start();        }        /// <summary>        /// loading last file task         /// </summary>        void LoadLastFiles()        {            var files = Directory.EnumerateFileSystemEntries(testPath);                        DateTime dtBegin = DateTime.Now;            LogHelper.Log("1====loading begin:");            foreach (var pageFile in files)            {                Invoke(delegate                {                    allFiles1.Add(GetFileItem(pageFile));                });            }            LogHelper.Log("1====loading ok:" + (DateTime.Now - dtBegin).TotalSeconds);            LogHelper.Log("1====current ItemsCount:" + allFiles1.Count.ToString());        }        #endregion

 

6.list 也放在线程中,这个需要传递Listview过来,刷新Items,如下

技术分享
   #region datasource 2        /// <summary>        /// files and directories in current directory, display in listview        /// </summary>        List<FileItem> allFiles2 = new List<FileItem>();        /// <summary>        ///  files and directories in current directory, display in listview        /// </summary>        public List<FileItem> AllFiles2        {            get { return allFiles2; }            set            {                if (allFiles2 != value)                    allFiles2 = value;                NotifyPropertyChanged("AllFiles2");            }        }        #endregion        #region load data method---2        /// <summary>        /// when current directory path change ,refresh listview        /// </summary>        public void Refresh2()        {            //LoadLastFiles2();            Thread thread2 = new Thread(new ThreadStart(LoadLastFiles2));            thread2.Start();        }        /// <summary>        /// loading last file task         /// </summary>        void LoadLastFiles2()        {            var files = Directory.EnumerateFileSystemEntries(testPath);           allFiles2   = new List<FileItem>();            DateTime dtBegin = DateTime.Now;            DateTime dtLastRefresh = DateTime.Now;            LogHelper.Log("2====loading begin:");            foreach (string file in files)            {                allFiles2.Add(GetFileItem(file));                NotifyPropertyChanged("AllFiles2");                Invoke(delegate                {                    this.tstLv.Items.Refresh();                });                dtLastRefresh = DateTime.Now;            }            NotifyPropertyChanged("AllFiles2");            LogHelper.Log("2====loading ok:" + (DateTime.Now - dtBegin).TotalSeconds);            LogHelper.Log("2====current ItemsCount:" + AllFiles2.Count.ToString());        }        #endregion

 

经过多轮测试,发现list明显速度比较慢

04:42:02 493 | 1====loading begin:

04:42:05 287 | 1====loading ok:2.7932793

04:42:05 288 | 1====current ItemsCount:73338

04:42:07 192 | 2====loading begin:

04:42:26 276 | 2====loading ok:19.0839082

04:42:26 277 | 2====current ItemsCount:73338

 

04:42:43 277 | 2====loading begin:

04:43:04 188 | 2====loading ok:20.9110909

04:43:04 189 | 2====current ItemsCount:73338

04:43:05 838 | 1====loading begin:

04:43:08 511 | 1====loading ok:2.6732673

04:43:08 512 | 1====current ItemsCount:73338

这一次,ObserableCollection 的优势非常明显。

7. 使用list时,每增加一个数据,就refresh一下,这里有点浪费了。
有两个办法:一是每加载若干数据(例如200个)refresh一次,而是每过0.1秒refresh一次。考虑到用户的操作,0.1秒内用户操作的可能性小的多,必将手没那么快。
分时加载 list 优化的代码如下:

技术分享
 void LoadLastFiles2()        {            var files = Directory.EnumerateFileSystemEntries(testPath);           allFiles2   = new List<FileItem>();            DateTime dtBegin = DateTime.Now;            DateTime dtLastRefresh = DateTime.Now;            LogHelper.Log("2====loading begin:");            foreach (string file in files)            {                allFiles2.Add(GetFileItem(file));                NotifyPropertyChanged("AllFiles2");                if ((DateTime.Now - dtLastRefresh).TotalSeconds > 0.1)                {                    Invoke(delegate                    {                        this.tstLv.Items.Refresh();                    });                    dtLastRefresh = DateTime.Now;                }            }            NotifyPropertyChanged("AllFiles2");            LogHelper.Log("2====loading ok:" + (DateTime.Now - dtBegin).TotalSeconds);            LogHelper.Log("2====current ItemsCount:" + AllFiles2.Count.ToString());        }

这次对比,实在是差别太大了:

04:46:57 739 | 1====loading begin:

04:47:00 388 | 1====loading ok:2.650265

04:47:00 389 | 1====current ItemsCount:73338

04:47:03 612 | 2====loading begin:

04:47:03 853 | 2====loading ok:0.2410241

04:47:03 854 | 2====current ItemsCount:73338

 

 04:47:20 351 | 2====loading begin:

04:47:20 641 | 2====loading ok:0.290029

04:47:20 662 | 2====current ItemsCount:73338

 04:47:23 235 | 1====loading begin:

04:47:25 875 | 1====loading ok:2.640264

04:47:25 876 | 1====current ItemsCount:73338  

看来分时加载,有点意思。

再来看看分数据量加载:

 代码:

技术分享List

结果

04:54:03 480 | 1====loading begin:

04:54:06 056 | 1====loading ok:2.5762576

04:54:06 057 | 1====current ItemsCount:73338

 04:54:07 112 | 2====loading begin:

04:54:07 429 | 2====loading ok:0.3170317

04:54:07 430 | 2====current ItemsCount:73338

 

 04:54:24 489 | 2====loading begin:

04:54:24 789 | 2====loading ok:0.3010301

04:54:24 790 | 2====current ItemsCount:73338

 04:54:26 486 | 1====loading begin:

04:54:29 176 | 1====loading ok:2.690269

04:54:29 177 | 1====current ItemsCount:73338

看来还是要 设定refresh的时机, 这样子速度快了不少。

至于分数据还是分时,看实际的需要了,个人认为分时比较好。

分时的时间最好长一点,数据量分块也大一点,减少刷新UI的时间,加载会快。

但是如果用户同时 拖拽滚动条, 体验就不好了,不流畅,滚动条会跳跃。

8. ObservableCollection 也有优化的方案,如下,采用延迟通知数据变化的方案。网上看到的,很抱歉,没找到出处。

技术分享RangeObservableCollection

修改代码如下:

技术分享Load1

 

测试后发现,效果并不明显:

05:05:08 989 | 1====loading begin:

05:05:13 189 | 1====loading ok:4.2

05:05:13 191 | 1====current ItemsCount:73338

所以,还是束之高阁吧。

 

唠唠叨叨这么多,其实呢,对于大数据加载,MS提供的ObservableCollection方案还是不错的,但是呢,想要再快一点,还是自己来搞搞把。

另外呢,ObservableCollection为什么快,网上不少资料,研究吧。

欢迎拍砖!!

转载:数据的加载性能比较