You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何加速MD5全零前缀哈希查找代码?解决速度骤降问题

MD5前缀全零哈希查找的性能优化方案

问题背景

我出于爱好写了一段查找前缀全零MD5哈希的C#代码,运行首秒能算约4亿次MD5哈希,但之后速度骤降到约1000万次/秒。已经试过批量缓冲区复用MD5对象、线程绑定核心这些优化,考虑过ILGPU的GPU加速但觉得太复杂,想找更简单有效的加速方案。

核心优化方案

  • 替换随机数生成器:当前用的加密级随机数生成器是核心性能瓶颈,改用Xoshiro256++这类高性能伪随机数生成器,速度比加密级RNG快几十倍,完全满足碰撞查找的随机性需求。
  • 改用硬件加速的MD5实现:替换BouncyCastle的MD5Digest为.NET内置的MD5.Create(),它会自动利用CPU的SIMD/AES-NI硬件加速指令,性能远高于纯软件实现的MD5。
  • 减少全局变量竞争:全局计数器n的多线程修改会触发缓存一致性开销,给每个线程分配独立计数器,定期用Interlocked.Add原子更新全局统计,避免锁冲突。
  • 调整批量大小:原批量大小对应的400MB缓冲区远超CPU缓存容量,缩小到100万次/批(对应16MB内存),大幅提升缓存命中率。
  • 简化循环逻辑:去掉每次计算后的md5.Reset(),直接复用内置MD5对象的ComputeHash方法,内部已经做了状态重置的优化。

优化后的代码示例

using System;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

public class OptimizedMD5HashFinder
{
    private static readonly int numberOfThreads = Environment.ProcessorCount;
    private static readonly CancellationTokenSource cts = new CancellationTokenSource();
    private const int batchSize = 1000000; // 适配CPU缓存的批量大小
    private const int byteArraySize = 16;
    private static ulong totalHashes = 0;

    [DllImport("kernel32.dll")]
    private static extern IntPtr GetCurrentThread();

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr SetThreadAffinityMask(IntPtr hThread, IntPtr dwThreadAffinityMask);

    public static void Main(string[] args)
    {
        Console.WriteLine("启动多线程查找前缀全零的MD5哈希...");

        Task[] tasks = new Task[numberOfThreads];
        for (int i = 0; i < numberOfThreads; i++)
        {
            int coreId = i;
            tasks[i] = Task.Run(() => FindHash(coreId));
        }

        Task.WaitAll(tasks);
        Console.WriteLine("所有线程已完成或找到匹配项。");
        Console.ReadKey();
    }

    private static void FindHash(int coreId)
    {
        PinThreadToCore(coreId);
        using var md5 = MD5.Create(); // 启用硬件加速的MD5实现
        byte[] inputBuffer = new byte[byteArraySize];
        // 用线程ID和时间戳初始化伪随机数生成器,避免线程间重复序列
        var rng = new Xoshiro256PlusPlus((ulong)coreId, (ulong)DateTime.UtcNow.Ticks);
        ulong localCount = 0;

        while (!cts.Token.IsCancellationRequested)
        {
            for (int i = 0; i < batchSize; i++)
            {
                // 生成伪随机填充输入缓冲区
                rng.NextBytes(inputBuffer);
                
                // 计算MD5哈希
                byte[] hashBytes = md5.ComputeHash(inputBuffer);
                
                // 检查前4字节是否全零
                if (hashBytes[0] == 0 && hashBytes[1] == 0 && hashBytes[2] == 0 && hashBytes[3] == 0)
                {
                    Console.WriteLine($"\n线程 {coreId} 找到匹配项!");
                    Console.WriteLine($"随机字节: {BitConverter.ToString(inputBuffer).Replace("-", "").ToLower()}");
                    Console.WriteLine($"MD5哈希: {BitConverter.ToString(hashBytes).Replace("-", "").ToLower()}");
                    cts.Cancel();
                    return;
                }
                
                localCount++;
            }

            // 原子更新全局统计,避免线程竞争
            Interlocked.Add(ref totalHashes, (long)batchSize);
            if (totalHashes % 10000000 == 0)
            {
                Console.WriteLine($"已计算 {totalHashes:N0} 次哈希");
            }
        }
    }

    private static void PinThreadToCore(int coreId)
    {
        IntPtr mask = new IntPtr(1 << coreId);
        IntPtr thread = GetCurrentThread();
        SetThreadAffinityMask(thread, mask);
    }

    // 高性能伪随机数生成器 Xoshiro256++
    private class Xoshiro256PlusPlus
    {
        private ulong s0, s1, s2, s3;

        public Xoshiro256PlusPlus(ulong seed1, ulong seed2)
        {
            s0 = SplitMix64(ref seed1);
            s1 = SplitMix64(ref seed1);
            s2 = SplitMix64(ref seed1);
            s3 = SplitMix64(ref seed2);
        }

        private ulong SplitMix64(ref ulong x)
        {
            x += 0x9e3779b97f4a7c15;
            ulong z = x;
            z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
            z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
            return z ^ (z >> 31);
        }

        public ulong Next()
        {
            ulong result = RotateLeft(s0 + s3, 23) + s0;
            ulong t = s1 << 17;
            s2 ^= s0;
            s3 ^= s1;
            s1 ^= s2;
            s0 ^= s3;
            s2 ^= t;
            s3 = RotateLeft(s3, 45);
            return result;
        }

        public void NextBytes(byte[] buffer)
        {
            int i = 0;
            while (i < buffer.Length)
            {
                ulong val = Next();
                for (int j = 0; j < 8 && i < buffer.Length; j++)
                {
                    buffer[i++] = (byte)(val >> (j * 8));
                }
            }
        }

        private ulong RotateLeft(ulong x, int k)
        {
            return (x << k) | (x >> (64 - k));
        }
    }
}

内容的提问来源于stack exchange,提问作者user12316363

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:39:50