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

转载:ObservableCollection与List在加载数据上的性能比较

使用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为什么快,网上不少资料,研究吧。

欢迎拍砖!!

时间: 2024-07-30 02:48:38

转载:数据的加载性能比较的相关文章

将数据一次性加载到DataSet与逐行从DB内读取的性能比较

在开发中经常会遇到将当前处理批次的数据与数据库内的数据做校验的情况,通过有两种处理方式: 1.将待校验的数据一次性加载到DataSet,再将待校验的数据与DataSet内的数据逐行比较. 2.待校验数据在使用时,才从DB取出那一条数据进行比对. 第一种方法要每次在DataSet中查找数据,第二种直接定位到具体数据,两种方式在数据量为20W条记录的,第一种的处理时长是第二种的10倍. string strConnect = "Data Source=localhost;Initial Catalo

H5缓存机制浅析-移动端Web加载性能优化【干货】

转载:H5缓存机制浅析-移动端Web加载性能优化[干货] 作者:贺辉超,腾讯游戏平台与社区产品部 高级工程师 目录 1 H5缓存机制介绍 2 H5缓存机制原理分析 2.1 浏览器缓存机制 2.2 Dom Storgage(Web Storage)存储机制 2.3 Web SQL Database存储机制 2.4 Application Cache(AppCache)机制 2.5 Indexed Database (IndexedDB) 2.6 File System API 3 移动端Web加载

listview加载性能优化ViewHolder

在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局, 但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建. ListView加载数据都是在public View getView(int position, View convertView, ViewGroup parent) {}方法中进行的(要自定义listview都

移动端网站提升页面加载性能的优化技巧

移动端网站提升页面加载性能的优化技巧 收藏到:1时间:2015-06-17   文章来源:马海祥博客   访问次数:2501 网页性能的优化一直是网站成功的关键,越来越多的研究证明,不管是小型电商,还是大型连锁企业,即使是页面加载时间方面的细微改善,都可以带来更多的业务,更多的广告收入,更多的用户粘性和更多的客户满意度. 在过去几年,Web开发者都是基于改善硬件或者提高带宽速度来优化用户体验,但是最近几年,爆炸式的移动Web浏览器的使用打破了这个途径,低带宽,高延迟,小内存,低处理器性能的移动设

listview加载性能优化

在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建. ListView加载数据都是在public View getView(int position, View convertView, ViewGroup parent) {}方法中进行的(要自定义listview都需

WinForm ListView虚拟模式加载数据 提高加载速度

将VirtualMode 属性设置为 true 会将 ListView 置于虚拟模式.控件不再使用Collection.Add()这种方式来添加数据,取而代之的是使用RetrieveVirtualItem(Occurs when the ListView is in virtual mode and requires a ListViewItem.)和CacheVirtualItems两个事件,单独使用RetrieveVirtualItem也可以,CacheVirtualItems这个事件主要是

GreenPlum 使用gpload通过gpfdist文件实现数据高速加载

1,gpload环境准备 环境准备请参考博主以前的文章gpfdist部署实战:http://blog.csdn.net/mchdba/article/details/72540806  ,安装好gpfdist后,gpload也自动有了,可以自动使用. 安装完后,可以启动gpfdist服务:nohup /data/greenplum/bin/gpfdist -d /data/greenplum/ -p 8090> /home/gpadmin/gpfdist.log  & 2,gpload简介

H5 缓存机制浅析 移动端 Web 加载性能优化

1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5 引入的离线存储,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问. H5 应用程序缓存为应用带来三个优势: 离线浏览 用户可在应用离线时使用它们 速度 已缓存资源加载得更快 减少服务器负载 浏览器将只从服务器下载更新过或更改过的资源. 根据标准,到目前为止,H5 一共有6种缓存机制,有些是之前已有,有些是 H5 才新加入的. 浏览

【Android笔记】listview加载性能优化及有多种listitem布局处理方式

在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容. 用户可以自由的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建. ListView加载数据都是在 1 public View getView(int position, View convertView, ViewGroup parent) { 2 3 ...... 4 5 }