Created
March 6, 2019 20:35
-
-
Save discostu105/69103b549a392182fbfa2b09d11cee2f to your computer and use it in GitHub Desktop.
Parsing exercise
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using BenchmarkDotNet.Attributes; | |
using System; | |
using System.Globalization; | |
using System.Linq; | |
using System.Runtime.CompilerServices; | |
namespace ConsoleApp4 { | |
//[ShortRunJob] | |
[MemoryDiagnoser] | |
public class Program { | |
static void Main(string[] args) { | |
BenchmarkDotNet.Running.BenchmarkRunner.Run<Program>(); | |
BenchmarkDotNet.Running.BenchmarkRunner.Run<ParsingPerf>(); | |
} | |
[Benchmark] | |
public void Original() { | |
string[] machineIdPart; | |
string[] employeeIdPart; | |
long machineId; | |
long employeeId; | |
//Input String | |
var description = "machineId: 276744, engineId: 59440, employeeId: 4619825"; | |
var infoList = description.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); | |
foreach (var info in infoList) { | |
if (info.TrimStart().StartsWith("machineId", StringComparison.OrdinalIgnoreCase)) { | |
machineIdPart = info.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); | |
if (machineIdPart.Count() > 1) { | |
long.TryParse(machineIdPart[1].Trim(), out machineId); | |
} | |
} | |
if (info.TrimStart().StartsWith("employeeId", StringComparison.OrdinalIgnoreCase)) { | |
employeeIdPart = info.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); | |
if (employeeIdPart.Count() > 1) { | |
long.TryParse(employeeIdPart[1].Trim(), out employeeId); | |
} | |
} | |
} | |
} | |
[Benchmark] | |
public void Answer() { | |
long machineId = 0; | |
long employeeId = 0; | |
var description = "machineId: 276744, engineId: 59440, employeeId: 4619825"; | |
ReadOnlySpan<char> descriptionSpan = description.AsSpan(); | |
var nameValueBlockStartIndex = 0; | |
while (nameValueBlockStartIndex < description.Length) { | |
var blockEndIndex = description.IndexOf(',', nameValueBlockStartIndex); | |
if (blockEndIndex == -1) { | |
blockEndIndex = description.Length; | |
} | |
var namePartEndIndex = description.IndexOf(':', nameValueBlockStartIndex); | |
var namePartLength = namePartEndIndex - nameValueBlockStartIndex; | |
var namePart = descriptionSpan.Slice(nameValueBlockStartIndex, namePartLength); | |
var valuePartStartIndex = namePartEndIndex + 1; | |
var valuePartLength = blockEndIndex - valuePartStartIndex + 1; | |
var valuePart = descriptionSpan.Slice(valuePartStartIndex, valuePartLength - 1); | |
while (namePart[0] == ' ') { | |
namePart = namePart.Slice(1); | |
} | |
if (namePart.Equals("machineId", StringComparison.OrdinalIgnoreCase)) { | |
Int64.TryParse(valuePart, out machineId); | |
} else if (namePart.Equals("employeeId", StringComparison.OrdinalIgnoreCase)) { | |
Int64.TryParse(valuePart, out employeeId); | |
} | |
nameValueBlockStartIndex = blockEndIndex + 1; | |
} | |
} | |
[Benchmark] | |
public void MyAnswerFastParser() { | |
long machineId = 0; | |
long employeeId = 0; | |
var description = "machineId: 276744, engineId: 59440, employeeId: 4619825"; | |
var span = description.AsSpan(); | |
while (span.Length > 0) { | |
var entry = span.SplitNext(','); | |
var key = entry.SplitNext(':').TrimStart(' '); | |
var value = entry.TrimStart(' '); | |
if (key.Equals("machineId", StringComparison.Ordinal)) { | |
machineId = ParsingPerf.LongParseFast(value); | |
} | |
if (key.Equals("employeeId", StringComparison.Ordinal)) { | |
employeeId = ParsingPerf.LongParseFast(value); | |
} | |
} | |
} | |
[Benchmark] | |
public void MyAnswer() { | |
long machineId = 0; | |
long employeeId = 0; | |
var description = "machineId: 276744, engineId: 59440, employeeId: 4619825"; | |
var span = description.AsSpan(); | |
while (span.Length > 0) { | |
var entry = span.SplitNext(','); | |
var key = entry.SplitNext(':').TrimStart(' '); | |
var value = entry.TrimStart(' '); | |
if (key.Equals("machineId", StringComparison.Ordinal)) { | |
long.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out machineId); | |
} | |
if (key.Equals("employeeId", StringComparison.Ordinal)) { | |
long.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out employeeId); | |
} | |
} | |
} | |
} | |
public static class Extensions { | |
public static ReadOnlySpan<char> SplitNext(this ref ReadOnlySpan<char> span, char seperator) { | |
int pos = span.IndexOf(seperator); | |
if (pos > -1) { | |
var part = span.Slice(0, pos); | |
span = span.Slice(pos + 1); | |
return part; | |
} else { | |
var part = span; | |
span = span.Slice(span.Length); | |
return part; | |
} | |
} | |
} | |
//[ShortRunJob] | |
[MemoryDiagnoser] | |
public class ParsingPerf { | |
private static readonly string s = "4619825"; | |
private static long result; | |
private static ulong uresult; | |
[Benchmark] | |
public void Parse() { | |
result = long.Parse(s); | |
} | |
[Benchmark] | |
public void TryParse() { | |
long.TryParse(s, out result); | |
} | |
[Benchmark] | |
public void TryParseInvariantCulture() { | |
long.TryParse(s, NumberStyles.None, CultureInfo.InvariantCulture, out result); | |
} | |
[Benchmark] | |
public void TryParseInvariantCultureUnsighed() { | |
ulong.TryParse(s, NumberStyles.None, CultureInfo.InvariantCulture, out uresult); | |
} | |
[Benchmark] | |
public void ParseFast() { | |
result = LongParseFast(s); | |
} | |
public static long LongParseFast(ReadOnlySpan<char> value) { | |
long result = 0; | |
for (int i = 0; i < value.Length; i++) { | |
result = 10 * result + (value[i] - 48); | |
} | |
return result; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment