[英]Parallel.ForEach use case
I am wondering if I should be using Parallel.ForEach()
for my case.我想知道我是否应该为我的案例使用Parallel.ForEach()
。 For a bit of context: I am developing a small music player using the NAudio library.关于上下文:我正在使用 NAudio 库开发一个小型音乐播放器。 I want to use Parallel.ForEach()
in a factory method to quickly access .mp3 files and create TrackModel
objects to represent them (about 400).我想在工厂方法中使用Parallel.ForEach()
来快速访问 .mp3 文件并创建TrackModel
对象来表示它们(大约 400 个)。 The code looks like this:代码如下所示:
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;
}
Note: I use lock
to prevent multiple Threads from adding elements to the list at the same time.注意:我使用lock
来防止多个线程同时向列表添加元素。
My question is the following: Should I be using Parallel.ForEach()
in this situation or am I better off writing a normal foreach loop?我的问题如下:在这种情况下我应该使用Parallel.ForEach()
还是编写一个普通的 foreach 循环更好? Is this the right approach to achieve better performance and should I be using multithreading in combination with file access in the first place?这是实现更好性能的正确方法吗?我应该首先将多线程与文件访问结合使用吗?
You're better off avoiding both a foreach
and Parallel.ForEach
.你最好避免同时使用foreach
和Parallel.ForEach
。 In this case AsParallel()
is your friend.在这种情况下AsParallel()
是您的朋友。
Try this:尝试这个:
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();
}
This handles all the parallel logic and the locking behind the scenes for you.这将为您处理所有并行逻辑和幕后锁定。
Combining the suggestion from comments and answers and adapting them to my code I was able to solve my issue with the following code:结合来自评论和答案的建议并将它们调整到我的代码中,我能够使用以下代码解决我的问题:
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;
}
Using AsParallel()
helped significantly decrease the loading time which is what I was looking for.使用AsParallel()
有助于显着减少我正在寻找的加载时间。 I will mark Enigmativity 's answer as correct because of the clever idea.由于这个聪明的想法,我会将Enigmativity的答案标记为正确。 Initially, it threw a weird AggregateException
, but I was able to solve it by saving the output in a variable and then returning it.最初,它抛出了一个奇怪的AggregateException
,但我能够通过将输出保存在变量中然后返回它来解决它。
Credit to marsze as well, whose suggestion helped me fix a memory leak in the application and shave off 16MB of memory (!).还要感谢 marsze ,他的建议帮助我修复了应用程序中的内存泄漏并减少了 16MB 的内存(!)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.