创建大型列表<t> </t>

时间:2014-01-19 01:12:13

标签: c# wpf performance linq list

我有以下代码:

var lstMusicInfo = new List<MediaFile>();
var LocalMusic = Directory.EnumerateFiles(AppSettings.Default.ComputerMusicFolder, "*.*", SearchOption.AllDirectories).AsParallel().ToList<string>();
LocalMusic = (from a in LocalMusic.AsParallel()
              where a.EndsWith(".mp3") || a.EndsWith(".wma")
              select a).ToList<string>();
var DeviceMusic = adb.SyncMedia(this.dev, AppSettings.Default.ComputerMusicFolder, 1);

Parallel.ForEach(LocalMusic, new Action<string>(item =>
    {
        try
        {
            UltraID3 mFile = new UltraID3();
            FileInfo fInfo;
            mFile.Read(item);
            fInfo = new FileInfo(item);
            bool onDevice = true;
            if (DeviceMusic.Contains(item))
            {
                onDevice = false;
            }
            // My Problem starts here
            lstMusicInfo.Add(new MediaFile()
            {
                Title = mFile.Title,
                Album = mFile.Album,
                Year = mFile.Year.ToString(),
                ComDirectory = fInfo.Directory.FullName,
                FileFullName = fInfo.FullName,
                Artist = mFile.Artist,
                OnDevice = onDevice,
                PTDevice = false
            });
            //Ends here.
        }
        catch (Exception) { }
    }));
    this.Dispatcher.BeginInvoke(new Action(() =>
    {
        lstViewMusicFiles.ItemsSource = lstMusicInfo;
        blkMusicStatus.Text = "";
        doneLoading = true;
    }));
    #endregion
}));

代码的第一部分给出了几乎即时的结果:

  1. 计算机上有5780个文件的地址。

  2. 获取Android设备上所有音乐文件的列表,将其与这些5780文件进行比较,并返回在计算机上找到但未在设备上找到的文件列表(在我的情况下,它会返回包含5118项的列表)。


  3. 下面的代码块是我的问题,我将数据填充到一个类中,然后将该类添加到List<T>中,执行5780次需要60秒,我该如何改进它?

    // My Problem starts here
    lstMusicInfo.Add(new MediaFile
        {
            Title = mFile.Title,
            Album = mFile.Album,
            Year = mFile.Year.ToString(),
            ComDirectory = fInfo.Directory.FullName,
            FileFullName = fInfo.FullName,
            Artist = mFile.Artist,
            OnDevice = onDevice,
            PTDevice = false
        });
    //Ends here.
    

    更新 这是分析结果,我看到它显然为什么它减慢了&gt; _&gt; 我想我应该寻找一个不同的库来读取音乐文件信息。

    enter image description here

2 个答案:

答案 0 :(得分:2)

避免一次性加载所有内容的一种方法是在必要时延迟加载ID3信息。

您构建了MediaFile实例,因此......

new MediaFile(filePath)

... MediaFile看起来像下面这样。

internal sealed class MediaFile
{
    private readonly Lazy<UltraID3> _lazyFile;

    public MediaFile(string filePath)
    { 
        _lazyFile = new Lazy<UltraID3>(() =>
        {
            var file = new UltraID3();
            file.Read(filePath);
            return file;
        });
    }

    public string Title
    {
        get { return _lazyFile.Value.Title; }
    }

    // ...
}

这可能不如在后台尽可能快地加载它们那么理想,如果你执行类似MediaFiles.OrderBy(x => x.Title).ToList()的操作并且没有任何延迟加载,那么你将不得不等待加载每个文件。 / p>

将它们加载到后台会使它们在后台加载完成后立即可用。但是,在后台加载完成之前,您可能不得不关注自己没有访问某些项目。

答案 1 :(得分:2)

您最大的瓶颈是new FileInfo(item),但您不需要FileInfo来获取目录和文件名。您可以使用Path.GetDirectoryNamePath.GetFileName,因为不涉及I / O,所以必须加快速度。

                UltraID3 mFile = new UltraID3();
                //FileInfo fInfo;
                mFile.Read(item);
                //fInfo = new FileInfo(item);
                bool onDevice = true;
                if (DeviceMusic.Contains(item))
                {
                    onDevice = false;
                }
                // My Problem starts here
                lstMusicInfo.Add(new MediaFile()
                {
                    Title = mFile.Title,
                    Album = mFile.Album,
                    Year = mFile.Year.ToString(),
                    ComDirectory = Path.GetDirectoryName(item), // fInfo.Directory.FullName,
                    FileFullName = Path.GetFileName(item), //fInfo.FullName,
                    Artist = mFile.Artist,
                    OnDevice = onDevice,
                    PTDevice = false
                });
                //Ends here.