Почему хеширование записи F # возвращает разные значения при каждом запуске - PullRequest
4 голосов
/ 28 июня 2019

Я пытаюсь создать простой кэш на диске, но каждый раз, когда я запускаю приложение, мои структурно равные записи имеют разные значения хеш-функции.

Поведение кажется правильным (детерминированным), когда язапустите его в LINQPad или, если запись содержит только целое число.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="Program.fs" />
  </ItemGroup>

</Project>
type Test = { test : string }

[<EntryPoint>]
let main argv =
    { test = "test" }
    |> hash
    |> printfn "%i"

    0

Я ожидаю, что выполнение hash для структурно равных записей всегда будет возвращать одно и то же значение.

1 Ответ

4 голосов
/ 29 июня 2019

F # underneat использует стандартные функции хеширования .NET.У них есть специальное рандомизированное начальное число, применяемое при каждом запуске нового процесса (или AppDomain в старой платформе .NET).Это делает их непоследовательными в разных процессах.Причиной этого является безопасность: оставление хэша без изменений было бы уязвимостью, которую можно использовать, например, для.детерминированные хеш-атаки.

Если вы хотите иметь быстрые согласованные хэши, вам понадобится что-то вроде Murmur3 или CityHash.Они очень быстро хэшируют любую последовательность байтов и обеспечивают довольно хорошее предотвращение столкновений.Однако они не поддерживаются "из коробки" в F # / .NET.

Если вы хотите использовать что-то, что уже существует в стандартной библиотеке .NET, вы, вероятно, можете использовать MD5, но имейте в виду, что это скоростьгораздо слабее, чем два выше.Он также считается более подверженным столкновениям.

...