Browse Source

introducing ParallelFor.WithTemporalBuffer(): common utility for the parallel buffer reusal trick

af/merge-core
Anton Firszov 8 years ago
parent
commit
09d993b503
  1. 60
      src/ImageSharp/Common/Helpers/ParallelFor.cs
  2. 13
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

60
src/ImageSharp/Common/Helpers/ParallelFor.cs

@ -0,0 +1,60 @@
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Utility methods for Parallel.For() execution. Use this instead of raw <see cref="Parallel"/> calls!
/// </summary>
internal static class ParallelFor
{
/// <summary>
/// Helper method to execute Parallel.For using the settings in <see cref="Configuration.ParallelOptions"/>
/// </summary>
public static void WithConfiguration(int fromInclusive, int toExclusive, Configuration configuration, Action<int> body)
{
Parallel.For(fromInclusive, toExclusive, configuration.ParallelOptions, body);
}
/// <summary>
/// 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.
/// </summary>
/// <typeparam name="T">The value type of the buffer</typeparam>
/// <param name="fromInclusive">The start index, inclusive.</param>
/// <param name="toExclusive">The end index, exclusive.</param>
/// <param name="configuration">The <see cref="Configuration"/> used for getting the <see cref="MemoryManager"/> and <see cref="ParallelOptions"/></param>
/// <param name="bufferLength">The length of the requested parallel buffer</param>
/// <param name="body">The delegate that is invoked once per iteration.</param>
public static void WithTemporalBuffer<T>(
int fromInclusive,
int toExclusive,
Configuration configuration,
int bufferLength,
Action<int, IBuffer<T>> body)
where T : struct
{
MemoryManager memoryManager = configuration.MemoryManager;
ParallelOptions parallelOptions = configuration.ParallelOptions;
IBuffer<T> InitBuffer()
{
return memoryManager.Allocate<T>(bufferLength);
}
void CleanUpBuffer(IBuffer<T> buffer)
{
buffer.Dispose();
}
IBuffer<T> BodyFunc(int i, ParallelLoopState state, IBuffer<T> buffer)
{
body(i, buffer);
return buffer;
}
Parallel.For(fromInclusive, toExclusive, parallelOptions, InitBuffer, BodyFunc, CleanUpBuffer);
}
}
}

13
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<Vector4>(source.Width),
(int y, ParallelLoopState sate, IBuffer<Vector4> tempRowBuffer) =>
configuration,
source.Width,
(int y, IBuffer<Vector4> tempRowBuffer) =>
{
Span<Vector4> firstPassRow = firstPassPixels.GetRowSpan(y);
Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
@ -157,10 +157,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
firstPassRow[x] = window.ComputeWeightedRowSum(tempRowSpan, sourceX);
}
}
return tempRowBuffer;
},
(IBuffer<Vector4> tmp) => tmp.Dispose());
});
// Now process the rows.
Parallel.For(

Loading…
Cancel
Save