diff --git a/RecordParser/Engines/ExpressionHelper.cs b/RecordParser/Engines/ExpressionHelper.cs index af3171f..72d563f 100644 --- a/RecordParser/Engines/ExpressionHelper.cs +++ b/RecordParser/Engines/ExpressionHelper.cs @@ -9,13 +9,13 @@ public static Expression Call(Delegate f, params Expression[] args) => Expression.Call(f.Target is null ? null : Expression.Constant(f.Target), f.Method, args); public static Expression StringAsSpan(Expression str) => - Expression.Call(typeof(MemoryExtensions), "AsSpan", Type.EmptyTypes, str); + Expression.Call(typeof(MemoryExtensions), nameof(MemoryExtensions.AsSpan), Type.EmptyTypes, str); public static Expression SpanAsString(Expression span) => Expression.Call(span, "ToString", Type.EmptyTypes); public static Expression Trim(Expression str) => - Expression.Call(typeof(MemoryExtensions), "Trim", Type.EmptyTypes, str); + Expression.Call(typeof(MemoryExtensions), nameof(MemoryExtensions.Trim), Type.EmptyTypes, str); public static Expression Slice(Expression span, Expression start) => Expression.Call(span, "Slice", Type.EmptyTypes, start); @@ -30,6 +30,6 @@ public static Expression Slice(Expression span, Expression start, Expression len Expression.Call(span, "Slice", Type.EmptyTypes, start, length); public static Expression IsWhiteSpace(Expression valueText) => - Expression.Call(typeof(MemoryExtensions), "IsWhiteSpace", Type.EmptyTypes, valueText); + Expression.Call(typeof(MemoryExtensions), nameof(MemoryExtensions.IsWhiteSpace), Type.EmptyTypes, valueText); } } diff --git a/RecordParser/Engines/Reader/PrimitiveTypeReaderEngine.cs b/RecordParser/Engines/Reader/PrimitiveTypeReaderEngine.cs index 1f1c0b1..4d9598e 100644 --- a/RecordParser/Engines/Reader/PrimitiveTypeReaderEngine.cs +++ b/RecordParser/Engines/Reader/PrimitiveTypeReaderEngine.cs @@ -78,7 +78,7 @@ private static Expression GetEnumFromSpanParseExpression(Type type, Expression s { var enumText = color.ToString(); - var compareTo = Expression.Call(typeof(MemoryExtensions), "CompareTo", Type.EmptyTypes, + var compareTo = Expression.Call(typeof(MemoryExtensions), nameof(MemoryExtensions.CompareTo), Type.EmptyTypes, StringAsSpan(Expression.Constant(enumText)), trim, Expression.Constant(StringComparison.OrdinalIgnoreCase)); diff --git a/RecordParser/Extensions/FileReader/ReaderCommon.cs b/RecordParser/Extensions/FileReader/ReaderCommon.cs index ddef2b1..d0686d0 100644 --- a/RecordParser/Extensions/FileReader/ReaderCommon.cs +++ b/RecordParser/Extensions/FileReader/ReaderCommon.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading; +using System.Threading.Tasks; namespace RecordParser.Extensions { @@ -44,6 +45,19 @@ private static IEnumerable Skip(this IEnumerable source, bool hasHeader ? source.Skip(1) : source; + public static ParallelOptions AsParallel(this ParallelismOptions option) + { + var query = new ParallelOptions(); + + if (option.MaxDegreeOfParallelism is { } degree) + query.MaxDegreeOfParallelism = degree; + + if (option.CancellationToken is { } token) + query.CancellationToken = token; + + return query; + } + public static ParallelQuery AsParallel(this IEnumerable source, ParallelismOptions option) { var query = source.AsParallel(); diff --git a/RecordParser/Extensions/FileWriter/WriterExtensions.cs b/RecordParser/Extensions/FileWriter/WriterExtensions.cs index 04f8345..4c1ad09 100644 --- a/RecordParser/Extensions/FileWriter/WriterExtensions.cs +++ b/RecordParser/Extensions/FileWriter/WriterExtensions.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; namespace RecordParser.Extensions { @@ -47,7 +48,10 @@ public static void WriteRecords(this TextWriter textWriter, IEnumerable it { if (options.Enabled) { - WriteParallel(textWriter, items, tryFormat, options); + if (options.EnsureOriginalOrdering) + WriteParallel(textWriter, items, tryFormat, options); + else + WriteParallelUnordered(textWriter, items, tryFormat, options); } else { @@ -55,6 +59,48 @@ public static void WriteRecords(this TextWriter textWriter, IEnumerable it } } + private class BufferContext + { + public char[] buffer; + public object lockObj; + } + + private static void WriteParallelUnordered(TextWriter textWriter, IEnumerable items, TryFormat tryFormat, ParallelismOptions options) + { + var poolSize = 10_000; + var textWriterLock = new object(); + var opt = options.AsParallel(); + var pool = Enumerable + .Range(0, poolSize) + .Select(_ => new BufferContext + { + buffer = new char[(int)Math.Pow(2, initialPow)], + lockObj = new object() + }) + .ToArray(); + + Parallel.ForEach(items, opt, (item, _, i) => + { + var x = pool[i % poolSize]; + + lock (x.lockObj) + { + retry: + + if (tryFormat(item, x.buffer, out var charsWritten)) + { + lock (textWriterLock) + textWriter.WriteLine(x.buffer, 0, charsWritten); + } + else + { + x.buffer = new char[x.buffer.Length * 2]; + goto retry; + } + } + }); + } + private static void WriteParallel(TextWriter textWriter, IEnumerable items, TryFormat tryFormat, ParallelismOptions options) { var poolSize = 10_000;