明明有更好的hash方法 有位朋友對(duì)我吐槽前幾天我列舉的在源生成器的生成db映射實(shí)體的優(yōu)化點(diǎn) 提前生成部分 hashcode 進(jìn)行比較 所示代碼 public static void GenerateReadTokens(this IDataReader reader, Span<int>
有位朋友對(duì)我吐槽前幾天我列舉的在源生成器的生成db映射實(shí)體的優(yōu)化點(diǎn) 提前生成部分 hashcode 進(jìn)行比較
所示代碼
public static void GenerateReadTokens(this IDataReader reader, Span s)
{
for (int i = 0; i < reader.FieldCount; i++)
{
var name = reader.GetName(i);
var type = reader.GetFieldType(i);
switch (EntitiesGenerator.SlowNonRandomizedHash(name))
{
case 742476188U:
s[i] = type == typeof(int) ? 1 : 2;
break;
case 2369371622U:
s[i] = type == typeof(string) ? 3 : 4;
break;
case 1352703673U:
s[i] = type == typeof(float) ? 5 : 6;
break;
default:
break;
}
}
}
這里為什么不用
string.GetHashCode
, 而要用
SlowNonRandomizedHash(name)
, 有更好的方法不用,真是傻
當(dāng)時(shí)俺也只能 囧 著臉給ta解釋
string.GetHashCode
真的沒辦法用,
可惜口頭幾句解釋再多,一時(shí)也無(wú)法擺脫ta鄙視的目光
只有在此多寫幾句“狡辯”
首先其實(shí)
NormalizedHash
性能很強(qiáng)的,其實(shí)現(xiàn)如下
public static uint SlowNonRandomizedHash(this string? value)
{
uint hash = 0;
if (!string.IsNullOrEmpty(value))
{
hash = 2166136261u;
foreach (char c in value!)
{
hash = (char.ToLowerInvariant(c) ^ hash) * 16777619;
}
}
return hash;
}
但是不管性能強(qiáng)不強(qiáng),也不是只能用這個(gè)方法的原因
其實(shí)真實(shí)原因很多人都知道,都是大家的默認(rèn)常識(shí)了:net code
string.GetHashCode
是隨機(jī)的,多次運(yùn)行程序,同一個(gè)字符串可能會(huì)在每次運(yùn)行都有不同的哈希值
比如 18年的文章 Why is string.GetHashCode() different each time I run my program in .NET Core?
這里簡(jiǎn)單復(fù)述一下原文內(nèi)容
以這個(gè)非常簡(jiǎn)單的程序?yàn)槔,它連續(xù)兩次調(diào)用一個(gè)字符串GetHashCode()
using System;
static class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!".GetHashCode());
Console.WriteLine("Hello World!".GetHashCode());
}
}
如果在 .NET Framework 上運(yùn)行此程序,則每次運(yùn)行該程序時(shí),都會(huì)獲得相同的值:
> dotnet run -c Release -f net471
-1989043627
-1989043627
> dotnet run -c Release -f net471
-1989043627
-1989043627
> dotnet run -c Release -f net471
-1989043627
-1989043627
相反,如果為 .NET Core 編譯同一程序,則在同一程序執(zhí)行中每次調(diào)用都會(huì)獲得相同的值,但對(duì)于不同的程序執(zhí)行,將獲得不同的值:GetHashCode()
> dotnet run -c Release -f netcoreapp2.1
-1105880285
-1105880285
> dotnet run -c Release -f netcoreapp2.1
1569543669
1569543669
> dotnet run -c Release -f netcoreapp2.1
-1477343390
-1477343390
努力查找之后,在 微軟官方文檔給出過(guò)使用GetHashCode()方法的建議 。其明確提示,不應(yīng)將GetHashCode()方法產(chǎn)生的hash值當(dāng)作為相同能持久化的值使用。
The hash code itself is not guaranteed to be stable. Hash codes for identical strings can differ across .NET implementations, across .NET versions, and across .NET platforms (such as 32-bit and 64-bit) for a single version of .NET. In some cases, they can even differ by application domain. This implies that two subsequent runs of the same program may return different hash codes.
Stephen Toub 在一個(gè) issue 中提到了這個(gè)問(wèn)題的答案:
Q: Why .NET Core utilize randomized string hashing?
問(wèn):為什么 .NET Core 使用隨機(jī)字符串哈希?
A: Security, prevention against DoS attacks, etc.
A:安全性、防止 DoS 攻擊等。
原文很詳細(xì)的解釋有關(guān)安全的內(nèi)容,這里就不作詳細(xì)復(fù)述了
當(dāng)然肯定是有的,string 類內(nèi)部其實(shí)就有,
感興趣的童鞋可以閱讀源碼 https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs#L923
里面 大小寫敏感和不敏感都有實(shí)現(xiàn), 其代碼比上面18年文章列舉的方法還有更多性能優(yōu)化
不過(guò)內(nèi)部方法,我們沒有辦法可以直接使用
但是呢? 我們有黑魔法可以直接使用
public static partial class StringHashing
{
[UnsafeAccessor(UnsafeAccessorKind.Method, Name = "GetNonRandomizedHashCodeOrdinalIgnoreCase")]
public static extern int Hash(this string c);
}
我們都寫到這里了,不比一下性能,大家肯定不服氣
來(lái)一段簡(jiǎn)單的比較
[ShortRunJob, MemoryDiagnoser, Orderer(summaryOrderPolicy: SummaryOrderPolicy.FastestToSlowest), GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory), CategoriesColumn]
public class StringHashingBenchmarks
{
[Params(0, 1, 10, 100)]
public int Count { get; set; }
public string Str { get; set; }
[GlobalSetup]
public void Setup()
{
var s = string.Join("", Enumerable.Repeat("_", Count));
var b = Encoding.UTF8.GetBytes(s);
Random.Shared.NextBytes(b);
Str = Encoding.UTF8.GetString(b);
}
[Benchmark(Baseline = true)]
public int GetHashCode()
{
return Str.GetHashCode();
}
[Benchmark]
public uint SlowNonRandomizedHash()
{
return Str.SlowNonRandomizedHash();
}
[Benchmark]
public int NonRandomizedHash()
{
return Str.Hash();
}
}
結(jié)果
BenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3)
13th Gen Intel Core i9-13900KF, 1 CPU, 32 logical and 24 physical cores
.NET SDK 9.0.100-preview.6.24328.19
[Host] : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2
ShortRun : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2
Job=ShortRun IterationCount=3 LaunchCount=1
WarmupCount=3
Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
---|---|---|---|---|---|---|---|---|
SlowNonRandomizedHash | 0 | 0.3286 ns | 0.0727 ns | 0.0040 ns | 0.69 | 0.01 | - | NA |
GetHashCode | 0 | 0.4751 ns | 0.1093 ns | 0.0060 ns | 1.00 | 0.00 | - | NA |
NonRandomizedHash | 0 | 0.6614 ns | 0.0339 ns | 0.0019 ns | 1.39 | 0.02 | - | NA |
GetHashCode | 1 | 0.5686 ns | 0.0881 ns | 0.0048 ns | 1.00 | 0.00 | - | NA |
NonRandomizedHash | 1 | 0.6559 ns | 0.0254 ns | 0.0014 ns | 1.15 | 0.01 | - | NA |
SlowNonRandomizedHash | 1 | 7.3752 ns | 0.2379 ns | 0.0130 ns | 12.97 | 0.11 | - | NA |
GetHashCode | 10 | 3.1627 ns | 0.2081 ns | 0.0114 ns | 1.00 | 0.00 | - | NA |
NonRandomizedHash | 10 | 16.1921 ns | 1.1773 ns | 0.0645 ns | 5.12 | 0.02 | - | NA |
SlowNonRandomizedHash | 10 | 44.4825 ns | 2.8742 ns | 0.1575 ns | 14.06 | 0.01 | - | NA |
GetHashCode | 100 | 40.4233 ns | 0.7217 ns | 0.0396 ns | 1.00 | 0.00 | - | NA |
NonRandomizedHash | 100 | 110.2494 ns | 13.1581 ns | 0.7212 ns | 2.73 | 0.02 | - | NA |
SlowNonRandomizedHash | 100 | 362.0329 ns | 11.0681 ns | 0.6067 ns | 8.96 | 0.02 | - | NA |
當(dāng)然,我們比較的 hash code 是大小寫敏感的, 而其他兩個(gè)是大小寫不敏感的,
但是其差距都非常小,所以可以說(shuō)都是很強(qiáng)的方法了
可惜
UnsafeAccessor
這些黑魔法無(wú)法在源生成器中使用
機(jī)器學(xué)習(xí):神經(jīng)網(wǎng)絡(luò)構(gòu)建(下)
閱讀華為Mate品牌盛典:HarmonyOS NEXT加持下游戲性能得到充分釋放
閱讀實(shí)現(xiàn)對(duì)象集合與DataTable的相互轉(zhuǎn)換
閱讀鴻蒙NEXT元服務(wù):論如何免費(fèi)快速上架作品
閱讀算法與數(shù)據(jù)結(jié)構(gòu) 1 - 模擬
閱讀5. Spring Cloud OpenFeign 聲明式 WebService 客戶端的超詳細(xì)使用
閱讀Java代理模式:靜態(tài)代理和動(dòng)態(tài)代理的對(duì)比分析
閱讀Win11筆記本“自動(dòng)管理應(yīng)用的顏色”顯示規(guī)則
閱讀本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]
湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2025 haote.com 好特網(wǎng)