太多了,只挑一部分感兴趣的吧。原文:https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-core-3-0/
{ReadOnly}Memory<T> 中获得 {ReadOnly}Span 性能改善ref T 的方法以及扩展方法 GetPinnableReference 的类型,可以使用 C# 7.3 的语法 fixed (T* = t) 来 pin 住内存。pin 住 span 性能提升
fixed (byte* p = s) // equivalent to `fixed (byte* p = &s.GetPinnableReference())`
MemoryMarshal.GetReference 能提高非空 span 获取引用的性能,因为少一个 null check
fixed (byte* p = &MemoryMarshal.GetReference(s))
Span<T> 的 SequenceCompareTo 和 SequenceEqual 方法 [PR]Vector 硬件优化再提高一倍。还可以使用 AVX 或 SSE 进一步同时处理更多数量的元素。
public int LoopLongs()
{
byte[] buffer = _buffer;
int remainingStart = 0;
if (IntPtr.Size == sizeof(long))
{
Span<long> longBuffer = MemoryMarshal.Cast<byte, long>(buffer);
remainingStart = longBuffer.Length * sizeof(long);
for (int i = 0; i < longBuffer.Length; i++)
{
if (longBuffer[i] != 0)
{
remainingStart = i * sizeof(long);
break;
}
}
}
for (int i = remainingStart; i < buffer.Length; i++)
{
if (buffer[i] != 0)
return i;
}
return -1;
}
public int LoopVectors()
{
byte[] buffer = _buffer;
int remainingStart = 0;
if (Vector.IsHardwareAccelerated)
{
while (remainingStart <= buffer.Length - Vector<byte>.Count)
{
var vector = new Vector<byte>(buffer, remainingStart);
if (!Vector.EqualsAll(vector, default))
{
break;
}
remainingStart += Vector<byte>.Count;
}
}
for (int i = remainingStart; i < buffer.Length; i++)
{
if (buffer[i] != 0)
return i;
}
return -1;
}
Span.CopyTo 性能提升Span<byte>.IndexOfAny 性能提升 [PR]Char 上,也同样应用到其他具有同样 size 的基本类型上Span<Char>.To{Upper/Lower}{Invariant}ReadOnlySpan<char>.Trim{Start/End} 性能大幅度提高{ReadOnly}Span<Char> 的相关性能提升Span.Reverse 和 Array.Reverse 性能提升Array.Clear 的性能 [PR]Array.{Last}IndexOf 在 byte 和 char 上的性能 [PR],以及把 IndexOf 优化推到跟 char 和 byte 同样 size 的基本类型string.IndexOf(Char, StringComparison.Ordinal) [PR] 并去除 allcate [PR]String.GetHashCode(StringComparison.Ordinal{IgnoreCase}) 的性能 [PR]String.Equals(string, StringComparison.OrdinalIgnoreCase) [PR]ReadOnlySpan<byte> [PR]
static ReadOnlySpan<byte> s_byteData => new byte[] { … /* constant bytes */ }
StringBuilder Append ReadOnlyMemory<char> 的装箱 [PR]。不过 StringBuilder 只是出于方便使用的,需要注重性能的场合,应该考虑使用 String.Create。另外,内部使用了一个 ValueStringBuilder,应该很快会公开了StringBuilder 的使用,下面这些得到了性能优化:Dns.GetHostEntry、DateTime.ToString(Hebrew)、PhysicalAddress.ToString、X509Certificate的各属性String.SubString 替换为 Span.Slice 去掉 FileSystemWatcher,将字符串的 allocation 推迟到必要的时候,同理 WebUtility.HtmlDecodeString.Concat 接受 ReadOnlySpan<char> 参数的版本,减少由此造成的 string 分配。Uri.DnsSafeHost、Path.ChangeExtension 受益Encoding.Unicode.GetString 和 Encoding.Preamble,翻新 UTF8Encoding 和 AsciiEncodingInt32、Int64、UInt32、UInt64 的 ParseToStringSystem.Decimal,改成全托管实现,加减乘除等各操作性能提升0..9 的 ToString() 直接返回 cache 好的字符串,因为这样的字符串在现实程序中大量存在Enum.Parse 和 Enum.TryParse,优化 [Flags] 枚举的 ToString,因此大幅度提高了枚举相关性能DateTime{Offset} 的 Parse 对于 o 和 r 格式大幅度提高TimeSpan、Guid 的 Parse 性能提高Guid 针对 byte 数组和 span 的构造函数 [PR]System.Text.RegularExpressions 中的 StringBuilder cache 实现替换为基于 ref struct 的 builder 实现,新 builder 利用 stack allocated 空间以及池化的 buffer [PR]。然后进一步使用 Span 推进。最大的改进来自于避免 RegexOptions.Compiled Regex 无端端的读取线程当前文化相关信息 [PR],这个跟 RegexOptions.IgnoreCase 一起使用更佳。现在基本不直接跟 thread 打交道了,所有留足了优化的空间
UnsafeQueueUserWorkItem 重载支持 IThreadPoolWorkItem 参数,让参数本身可以重用以避免分配System.Threading.Channels 的 ReadAsync 通过使用可重用的 IValueTaskSource 来支撑 ValueTask 返回,同时实现了 IThreadPoolWorkItem 并将自身当作加入队列,从而避免某种情况下的内存分配 [PR]async 和 await 的实现利用 IThreadPoolWorkItem 进一步减少分配,尤其在 ` TaskCreationOptions.RunContinuationsAsynchronously 的 TaskCompletionSourceawait Task.Yield() 无分配timer 注册队列分为即将触发和好一会才会触发两个,这样在触发 timer 时要处理的东西大幅度减少,而且避免了大量的锁争用ConcurrentDictionary<TKey, TValue> 的 IsEmpty 认为如果随便一个 bucket 非空,就无需锁定直接返回非空,避免每次都要获取锁从而争用。ConcurrentQueue<T> 在先判断 Count 再 TryDequeue 代码的性能问题ImmutableDictionary<TKey, TValue> 的查询变得更快,虽然还是没有 Dictionary<TKey, TValue> 那么快BitArray 的大量操作,Set 和 Get 进一步优化,Or、And 和 Xor 向量化SortedSet<T> 的 GetViewBetween 优化Comparer 的实现 [PR]Content-Length 时,HttpClient 使用更大的 buffer,在快速连接和大量数据的情况下,可以减少相当多的系统调用,从而性能大幅提高 [PR]SslStream 初始化优化,尤其在于分配方面IThreadPoolWorkItem 优化 Socket 在 Unix 系统下的表现,消除异步操作的 allocatedBinaryPrimitives.ReverseEndianness 使用 intrinsic 实现Stream.CopyTo 被改为 virtual 以允许子类优化。DeflateStream.CopyTo 优化BrotliStream 的 buffer,优化 ReadByte 和 WriteByte 避免分配StreamWriter 具有更多专门类型的重载避免分配ArrayPool<byte>.Shared 替代 System.IO.Pipelines 中的 MemoryPool<byte>.Shared,减少了间接层System.IO.Pipelines 上,进一步削减了 cpu 和内存的使用IPartition<T> 到 TakeLast 促进性能提升 [PR]Enumerable.Range(...).Select(…) 现在直接知道在 Enumerable 上操作,不需要额外 loop 处理Enumerable.Empty<T>() 的后接操作不处理SafeHandle 生命周期的操作从非托管代码转移到托管代码,避免每次传送的开销StringBuilder 的使用FileSystemWatcher 的 interopArray.CopyNullable<T> 的 GetValueOrDefault 比 Nullable<T>.Value 更快因为不需要检查有没有 ValueArray.Empty<T>()beforefieldinit,而类型标记为 beforefieldinit 对性能有好处,这样 runtime 就可以更灵活地处理初始化过程,以及决定要不要在访问类型的静态方法时加锁。[PR] [PR]Contains 替代 IndexOf;SocketsHttpHandler 使用 Environment.TickCount 替代 DateTime.UtcNow 来确定连接是否能重用,分辨率足够了ExecutionContext flowBitOperations 处理位操作static readonly 的基本类型当作 const 看待,对其进行优化。对于 static readonly base type 实例化为 derived type 的情况,调用其中虚拟方法时知道它的实际类型从而 devirtualize 甚至 inline 它
private static readonly Base s_base;
static Program() => s_base = new Derived();
[Benchmark]
public void AccessStatic() => s_base.Method();
private sealed class Derived : Base { public override void Method() { } }
private abstract class Base { public abstract void Method(); }
[Benchmark]
public int WrapUnwrap() => ValueTuple.Create(ValueTuple.Create(ValueTuple.Create(42))).Item1.Item1.Item1;