我现在正在用 TPL 类替换我的一个旧的并行化辅助类。当操作代码中发生错误时,我的旧代码已被证明非常不可靠,并且它似乎不是为我现在正在做的事情而构建的。
第一份工作清单很容易翻译成Parallel.ForEach
。但是这里有一个嵌套和索引循环,我无法轻易解决。
int streamIndex = 0;
foreach (var playlist in selectedPlaylists)
{
var localPlaylist = playlist;
foreach (var streamFile in playlist.StreamFiles)
{
var localStreamFile = streamFile;
var localStreamIndex = streamIndex++;
// Action that uses localPlaylist, localStreamFile and localStreamIndex
...
// Save each job's result to its assigned place in the list
lock (streamsList)
{
streamsList[localStreamIndex] = ...;
}
}
}
局部变量用于正确的闭包支持,因为 foreach 迭代变量是共享的。
我在想类似的事情
selectedPlaylists.SelectMany(p => p.StreamFiles)
但随后我失去了每个 streamFile 来自何处的关联,以及应该具有确定性的索引,因为它用于对结果列表中的结果进行排序。有没有办法保持这些与 Linq 的关联,并在枚举列表时添加该计数器?也许像这样(编造的伪代码):
selectedPlaylists
.SelectMany(p => new
{
Playlist = p,
StreamFile = ~~each one of p.StreamFiles~~,
Index = ~~Counter()~~
})
我可以保留那些旧的嵌套 foreach 循环并将所有作业收集到一个列表中,然后使用 Parallel.Invoke,但这似乎比需要的要复杂得多。我想知道是否有一个简单的 Linq 功能我还不知道。
好吧,你可以做这样的事情...
//
Dictionary<int, object> streamsList = new Dictionary<int, object>();
// First create a composition that holds the playlist and the streamfile
selectedPlaylists.SelectMany(playList => playList.StreamFiles.Select(streamFile => new { PlayList = playList, StreamFile = streamFile }))
// thenfor all of theese add the respective index
.Select((composition, i) => new { StreamFile = composition.StreamFile, PlayList = composition.PlayList, LocalStreamIndex = i })
.AsParallel()
.WithCancellation(yourTokenGoesHere)
.WithDegreeOfParallelism(theDegreeGoesHere)
.ForAll(indexedComposition =>
{
object result =somefunc(indexedComposition.LocalStreamIndex, indexedComposition.PlayList, indexedComposition.StreamFile);;
lock(streamsList) // dont call the function insde the lock or the as parallel is useless.
streamsList[indexedComposition.LocalStreamIndex] = result;
});
要展平StreamFiles
并保持与PlayList
关联并为其编制索引,您可以使用以下查询:
int index = 0;
var query = selectedPlaylists
.SelectMany(p => p.StreamFiles
.Select(s =>
new {
PlayList = p,
Index = index++,
StreamFile = s
}));