diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs index 56394502f..790c21da9 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs @@ -33,6 +33,7 @@ using static ICSharpCode.Decompiler.Metadata.MetadataExtensions; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.DebugInfo; +using System.Collections.Concurrent; namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler { @@ -205,7 +206,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler var progress = ProgressIndicator; DecompilerTypeSystem ts = new DecompilerTypeSystem(module, AssemblyResolver, Settings); Parallel.ForEach( - files, + Partitioner.Create(files, loadBalance: true), new ParallelOptions { MaxDegreeOfParallelism = this.MaxDegreeOfParallelism, CancellationToken = cancellationToken diff --git a/ILSpy/Commands/DecompileAllCommand.cs b/ILSpy/Commands/DecompileAllCommand.cs index ac263edf7..56a698e33 100644 --- a/ILSpy/Commands/DecompileAllCommand.cs +++ b/ILSpy/Commands/DecompileAllCommand.cs @@ -19,6 +19,7 @@ #if DEBUG using System; +using System.Collections.Concurrent; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -40,29 +41,32 @@ namespace ICSharpCode.ILSpy { Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); - Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) { - if (!asm.HasLoadError) { - Stopwatch w = Stopwatch.StartNew(); - Exception exception = null; - using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) { - try { - new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions() { FullDecompilation = true, CancellationToken = ct }); + Parallel.ForEach( + Partitioner.Create( MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), loadBalance: true), + new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, + delegate(LoadedAssembly asm) { + if (!asm.HasLoadError) { + Stopwatch w = Stopwatch.StartNew(); + Exception exception = null; + using (var writer = new System.IO.StreamWriter("c:\\temp\\decompiled\\" + asm.ShortName + ".cs")) { + try { + new CSharpLanguage().DecompileAssembly(asm, new Decompiler.PlainTextOutput(writer), new DecompilationOptions() { FullDecompilation = true, CancellationToken = ct }); + } + catch (Exception ex) { + writer.WriteLine(ex.ToString()); + exception = ex; + } } - catch (Exception ex) { - writer.WriteLine(ex.ToString()); - exception = ex; + lock (output) { + output.Write(asm.ShortName + " - " + w.Elapsed); + if (exception != null) { + output.Write(" - "); + output.Write(exception.GetType().Name); + } + output.WriteLine(); } } - lock (output) { - output.Write(asm.ShortName + " - " + w.Elapsed); - if (exception != null) { - output.Write(" - "); - output.Write(exception.GetType().Name); - } - output.WriteLine(); - } - } - }); + }); return output; }, ct)).Then(output => Docking.DockWorkspace.Instance.ShowText(output)).HandleExceptions(); } diff --git a/ILSpy/Commands/DisassembleAllCommand.cs b/ILSpy/Commands/DisassembleAllCommand.cs index 23319be78..e220ead0c 100644 --- a/ILSpy/Commands/DisassembleAllCommand.cs +++ b/ILSpy/Commands/DisassembleAllCommand.cs @@ -23,6 +23,8 @@ using System.Diagnostics; using System.Threading.Tasks; using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.Properties; +using System.Collections.Concurrent; + namespace ICSharpCode.ILSpy { [ExportMainMenuCommand(Menu = nameof(Resources._File), Header = nameof(Resources.DEBUGDisassemble), MenuCategory = nameof(Resources.Open), MenuOrder = 2.5)] @@ -37,8 +39,11 @@ namespace ICSharpCode.ILSpy { Docking.DockWorkspace.Instance.RunWithCancellation(ct => Task.Factory.StartNew(() => { AvalonEditTextOutput output = new AvalonEditTextOutput(); - Parallel.ForEach(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, delegate(LoadedAssembly asm) { - if (!asm.HasLoadError) { + Parallel.ForEach( + Partitioner.Create(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), loadBalance: true), + new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, + delegate (LoadedAssembly asm) { + if (!asm.HasLoadError) { Stopwatch w = Stopwatch.StartNew(); Exception exception = null; using (var writer = new System.IO.StreamWriter("c:\\temp\\disassembled\\" + asm.Text.Replace("(", "").Replace(")", "").Replace(' ', '_') + ".il")) { diff --git a/ILSpy/SolutionWriter.cs b/ILSpy/SolutionWriter.cs index 03ee32ab3..614076206 100644 --- a/ILSpy/SolutionWriter.cs +++ b/ILSpy/SolutionWriter.cs @@ -99,7 +99,12 @@ namespace ICSharpCode.ILSpy Stopwatch stopwatch = Stopwatch.StartNew(); try { - await Task.Run(() => Parallel.ForEach(assemblies, n => WriteProject(n, language, solutionDirectory, ct))) + // Explicitly create an enumerable partitioner here to avoid Parallel.ForEach's special cases for lists, + // as those seem to use static partitioning which is inefficient if assemblies take differently + // long to decompile. + await Task.Run(() => Parallel.ForEach(Partitioner.Create(assemblies), + new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount, CancellationToken = ct }, + n => WriteProject(n, language, solutionDirectory, ct))) .ConfigureAwait(false); await Task.Run(() => SolutionCreator.WriteSolutionFile(solutionFilePath, projects))