首页 > 解决方案 > Encoding.UTF8.GetBytes with Span - GetByteCount 或 try/catch 哪个对性能更好

问题描述

我正在尝试使用.NET Core 2.1 中的重载将 a 编码KeyValuePair<string, string>为 UTF-8 。key='value'Span<byte>

写这个GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes)方法的人显然是 Yoda 的弟子,因为TryGetBytes别无选择,这很奇怪,因为 Utf8Formatter 为所有非字符串原始类型提供了 TryWrite。

所以我有两种选择来编写扩展方法来做到这一点。

选项1:

public static bool TryGetBytes(this Encoding encoding, ReadOnlySpan<char> str, Span<byte> bytes, out int written)
{
  try
  {
    written = Encoding.UTF8.GetBytes(str, span);
    return true;
  }
  catch (ArgumentException)
  {
    written = 0;
    return false;
  }

选项 2:

public static bool TryGetBytes(this Encoding encoding, ReadOnlySpan<char> str, Span<byte> bytes, out int written)
{
  if (encoding.GetByteCount(str) > span.Length)
  {
    written = 0;
    return false;
  }

  written = Encoding.UTF8.GetBytes(str, span);
  return true;
}

假设“空间不足”的情况会在热路径上相当频繁地发生(例如,50 次中的 1 次),那么哪个对性能更好?

标签: c#.net-core

解决方案


当我写这个问题时,我想“你为什么不直接使用 BenchmarkDotNet 呢?” 所以我做了。

答:GetByteCount比 快两个数量级try/catch

结果如下:


BenchmarkDotNet=v0.11.3, OS=Windows 10.0.17763.253 (1809/October2018Update/Redstone5)
Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.2.102
  [Host]     : .NET Core 2.2.1 (CoreCLR 4.6.27207.03, CoreFX 4.6.27207.03), 64bit RyuJIT
  DefaultJob : .NET Core 2.2.1 (CoreCLR 4.6.27207.03, CoreFX 4.6.27207.03), 64bit RyuJIT


|   Method |        Mean |      Error |    StdDev | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
|--------- |------------:|-----------:|----------:|------------:|------------:|------------:|--------------------:|
| TryCatch | 40,985.9 ns | 800.034 ns | 785.74 ns |      0.4272 |           - |           - |              1392 B |
| TryCount |    366.5 ns |   8.450 ns |  10.38 ns |           - |           - |           - |                   - |

推荐阅读