From 09d993b503a186fd6a28f24c496d8476ce06a0ae Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 27 Feb 2018 00:37:23 +0100 Subject: [PATCH] introducing ParallelFor.WithTemporalBuffer(): common utility for the parallel buffer reusal trick --- src/ImageSharp/Common/Helpers/ParallelFor.cs | 60 +++++++++++++++++++ .../Processors/Transforms/ResizeProcessor.cs | 13 ++-- 2 files changed, 65 insertions(+), 8 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/ParallelFor.cs diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs new file mode 100644 index 0000000000..9a30b0b508 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/ParallelFor.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp +{ + /// + /// Utility methods for Parallel.For() execution. Use this instead of raw calls! + /// + internal static class ParallelFor + { + /// + /// Helper method to execute Parallel.For using the settings in + /// + public static void WithConfiguration(int fromInclusive, int toExclusive, Configuration configuration, Action body) + { + Parallel.For(fromInclusive, toExclusive, configuration.ParallelOptions, body); + } + + /// + /// Helper method to execute Parallel.For with temporal worker buffer in an optimized way. + /// The buffer will be only instantiated for each worker Task, the contents are not cleaned automatically. + /// + /// The value type of the buffer + /// The start index, inclusive. + /// The end index, exclusive. + /// The used for getting the and + /// The length of the requested parallel buffer + /// The delegate that is invoked once per iteration. + public static void WithTemporalBuffer( + int fromInclusive, + int toExclusive, + Configuration configuration, + int bufferLength, + Action> body) + where T : struct + { + MemoryManager memoryManager = configuration.MemoryManager; + ParallelOptions parallelOptions = configuration.ParallelOptions; + + IBuffer InitBuffer() + { + return memoryManager.Allocate(bufferLength); + } + + void CleanUpBuffer(IBuffer buffer) + { + buffer.Dispose(); + } + + IBuffer BodyFunc(int i, ParallelLoopState state, IBuffer buffer) + { + body(i, buffer); + return buffer; + } + + Parallel.For(fromInclusive, toExclusive, parallelOptions, InitBuffer, BodyFunc, CleanUpBuffer); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 0708a6c232..169496a982 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -128,12 +128,12 @@ namespace SixLabors.ImageSharp.Processing.Processors { firstPassPixels.Buffer.Clear(); - Parallel.For( + ParallelFor.WithTemporalBuffer( 0, sourceRectangle.Bottom, - configuration.ParallelOptions, - () => this.MemoryManager.Allocate(source.Width), - (int y, ParallelLoopState sate, IBuffer tempRowBuffer) => + configuration, + source.Width, + (int y, IBuffer tempRowBuffer) => { Span firstPassRow = firstPassPixels.GetRowSpan(y); Span sourceRow = source.GetPixelRowSpan(y); @@ -157,10 +157,7 @@ namespace SixLabors.ImageSharp.Processing.Processors firstPassRow[x] = window.ComputeWeightedRowSum(tempRowSpan, sourceX); } } - - return tempRowBuffer; - }, - (IBuffer tmp) => tmp.Dispose()); + }); // Now process the rows. Parallel.For(