JNA*_*JNA 0 .net c# memory parsing
我正在尝试从包含不同数字的单个字符串中解析不同的 ID(长),并且我需要最大限度地减少内存分配以提高性能。
下面是使用 Split 提取 ID 的代码,但我发现我可以使用 AsSpan 和 Splice 来执行相同的操作,而无需分配内存。但不幸的是,即使在网上查找后,我对这个 Span 概念也不太熟悉。谁能告诉我如何实现这一目标?
如下所示,输入字符串有 3 个不同的 ID,但我只需要其中 2 个并解析为长类型。
string[] machineIdPart;
string[] employeeIdPart;
long machineId;
long employeeId;
//Input String
var description = "machineId: 276744, engineId: 59440, employeeId: 4619825";
Console.Out.Write(description);
Console.Out.WriteLine();
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想修改此代码以最小化内存分配,因为此方法将非常频繁地运行。
此解决方案适用于 .NET Core 2.2。ReadOnlySpan<char>它在( )上使用了无分配扩展方法SplitNext。
public class Program {
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, out machineId);
}
if (key.Equals("employeeId", StringComparison.Ordinal)) {
long.TryParse(value, 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我通过 BenchmarkDotnet 比较了您的原始代码、现有答案和我的答案。它表明该解决方案确实是免分配的并且比原始版本执行得更快:
BenchmarkDotNet=v0.11.4, OS=Windows 10.0.17763.316 (1809/October2018Update/Redstone5)
Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), 1 CPU, 4 logical and 4 physical cores
.NET Core SDK=2.2.104
[Host] : .NET Core 2.2.2 (CoreCLR 4.6.27317.07, CoreFX 4.6.27318.02), 64bit RyuJIT
DefaultJob : .NET Core 2.2.2 (CoreCLR 4.6.27317.07, CoreFX 4.6.27318.02), 64bit RyuJIT
| Method | Mean | Error | StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|--------- |-----------:|----------:|----------:|------------:|------------:|------------:|--------------------:|
| Original | 1,164.1 ns | 11.606 ns | 10.289 ns | 0.2937 | - | - | 928 B |
| Answer | 460.5 ns | 4.527 ns | 4.234 ns | - | - | - | - |
| MyAnswer | 445.7 ns | 2.578 ns | 2.412 ns | - | - | - | - |
Run Code Online (Sandbox Code Playgroud)
除了字符串处理优化之外,还可以优化实际的解析功能。这将是一个更快的长解析器:
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;
}
Run Code Online (Sandbox Code Playgroud)
如果在我的示例中使用,它的性能将是216.0 ns我的基准测试中的两倍。当然,这个函数不能处理负数、逗号、点和其他语言环境之类的东西。但如果你同意的话,这可能是你能达到的最快速度。
| 归档时间: |
|
| 查看次数: |
660 次 |
| 最近记录: |