繁体   English   中英

Parallel.ForEach 用例

[英]Parallel.ForEach use case

我想知道我是否应该为我的案例使用Parallel.ForEach() 关于上下文:我正在使用 NAudio 库开发一个小型音乐播放器。 我想在工厂方法中使用Parallel.ForEach()来快速访问 .mp3 文件并创建TrackModel对象来表示它们(大约 400 个)。 代码如下所示:

public static List<TrackModel> CreateTracks(string[] files)
{
    // Guard Clause
    if (files == null || files.Length == 0) throw new ArgumentException();

    var output = new List<TrackModel>();

    TrackModel track;

    Parallel.ForEach(files, file =>
    {
        using (MusicPlayer musicPlayer = new MusicPlayer(file, 0f))
        {
             track = new TrackModel()
             {
                 FilePath = file,
                 Title = File.Create(file).Tag.Title,
                 Artist = File.Create(file).Tag.FirstPerformer,
                 TrackLength = musicPlayer.GetLengthInSeconds(),
             };
         }

         lock (output)
         {
             output.Add(track);
         }
   });

   return output;
}

注意:我使用lock来防止多个线程同时向列表添加元素。

我的问题如下:在这种情况下我应该使用Parallel.ForEach()还是编写一个普通的 foreach 循环更好? 这是实现更好性能的正确方法吗?我应该首先将多线程与文件访问结合使用吗?

你最好避免同时使用foreachParallel.ForEach 在这种情况下AsParallel()是您的朋友。

尝试这个:

public static List<TrackModel> CreateTracks(string[] files)
{
    if (files == null || files.Length == 0) throw new ArgumentException();

    return
        files
            .AsParallel()
            .AsOrdered()
            .WithDegreeOfParallelism(2)
            .Select(file =>
            {
                using (MusicPlayer musicPlayer = new MusicPlayer(file, 0f))
                {
                    return new TrackModel()
                    {
                        FilePath = file,
                        Title = File.Create(file).Tag.Title,
                        Artist = File.Create(file).Tag.FirstPerformer,
                        TrackLength = musicPlayer.GetLengthInSeconds(),
                    };
                }
            })
            .ToList();
}

这将为您处理所有并行逻辑和幕后锁定。

结合来自评论和答案的建议并将它们调整到我的代码中,我能够使用以下代码解决我的问题:

public List<TrackModel> CreateTracks(string[] files) 
{
    var output = files
                     .AsParallel()
                     .Select(file =>
                     {
                         using MusicPlayer musicPlayer = new MusicPlayer(file, 0f);
                         using File musicFile = File.Create(file);

                         return new TrackModel()
                         {
                             FilePath = file,
                             Title = musicFile.Tag.Title,
                             Artist = musicFile.Tag.FirstPerformer,
                             Length = musicPlayer.GetLengthInSeconds(),
                         };
                     })
                     .ToList();
    return output;

}

使用AsParallel()有助于显着减少我正在寻找的加载时间。 由于这个聪明的想法,我会将Enigmativity的答案标记为正确。 最初,它抛出了一个奇怪的AggregateException ,但我能够通过将输出保存在变量中然后返回它来解决它。

还要感谢 marsze ,他的建议帮助我修复了应用程序中的内存泄漏并减少了 16MB 的内存(!)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM