代码之家  ›  专栏  ›  技术社区  ›  Damovisa

随机数与之冲突。不同进程中的网络代码

  •  2
  • Damovisa  · 技术社区  · 16 年前

    在我开始之前,我想指出,我非常确定这确实发生了。我所有的日志都表明是这样。

    public class MyProcess
    {
        private System.Timers.Timer timer;
    
        // execution starts here
        public void EntryPoint()
        {
            timer = new System.Timers.Timer(15000);  // 15 seconds
            timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
            timer.AutoReset = false;
    
            Timer_Elapsed(this, null);
        }
    
        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            string uid = GetUID();
    
            // this bit of code sends a message to an external process.
            //  It uses the uid as an identifier - these shouldn't clash!
            CommunicationClass.SendMessage(uid);
    
            timer.Start();
        }
    
        // returns an 18 digit number as a string
        private string GetUID()
        {
            string rndString = "";
            Random rnd = new Random((int)DateTime.Now.Ticks);
            for (int i = 0; i < 18; i++)
            {
                rndString += rnd.Next(0, 10);
            }
            return rndString;
        }
    

    接收这些消息的外部进程感到困惑——我认为是因为同一uid来自两个单独的进程。基于此,似乎 GetUID()


    6 回复  |  直到 16 年前
        1
  •  5
  •   tvanfosson    16 年前

    除非有什么原因你不能,否则你应该考虑使用 GUID

    每条评论:您可以使用GUID和64位 FNV hash 和使用 XOR-folding 使您的结果在59位以内。不像GUID那样防碰撞,但比现有的要好。

        2
  •  7
  •   JP Alioto    16 年前

    你不想 随机 数字。我支持@JP。我认为你应该考虑使用GUID作为你的消息ID。

    编辑

        3
  •  3
  •   MusiGenesis    16 年前

    public static int GetSeed()
    {
        byte[] raw = Guid.NewGuid().ToByteArray();
        int i1 = BitConverter.ToInt32(raw, 0);
        int i2 = BitConverter.ToInt32(raw, 4);
        int i3 = BitConverter.ToInt32(raw, 8);
        int i4 = BitConverter.ToInt32(raw, 12);
        long val = i1 + i2 + i3 + i4;
        while (val > int.MaxValue)
        {
            val -= int.MaxValue;
        }
        return (int)val;
    }
    

    这基本上将Guid转换为int。理论上你可以得到重复的Guid,但这在很大程度上是不可能的。

    Guid.NewGuid().GetHashCode();
    

    在Windows编程中,以远远超出计时器实际精度的单位指定计时器的分辨率是很常见的(我第一次在Visual Basic 3.0的计时器控制中遇到这个问题,它以毫秒为单位设置,但实际上每秒只关闭18次)。我不确定,但我敢打赌,如果你只是运行一个循环并打印出DateTime。现在。Ticks,你会看到这些值以大约15ms的间隔量化。因此,有4个进程在运行,实际上很可能其中两个进程最终会在Random函数中使用完全相同的种子。

    如果你想担心不太可能发生的大规模事件,买彩票吧。

        4
  •  3
  •   rIPPER    16 年前

    实现这一点的另一种方法是不使用Random类,因为它充满了这样的问题。您可以使用System中提供的加密质量随机数生成器来实现相同的功能(随机18位数字)。安全。密码学。

    我已经修改了您的代码,使用RNGCryptoServiceProvider类来生成id。

    // returns an 18 digit number as a string
    private string GetUID()
    {
        string rndString = "";
        var rnd = new RNGCryptoServiceProvider();
        var data = new byte[18];
        rnd.GetBytes(data); 
        foreach(byte item in data)
        {
            rndString += Convert.ToString((int)item % 10);
        }
        return rndString;
    }
    
        5
  •  1
  •   Simeon Pilgrim    16 年前

    是的,它可能会发生,因此它确实发生了。

    您应该在启动时只初始化一次Random。如果您有多个线程同时启动,请获取DateTime的副本。现在。勾选并将其传递给每个具有已知偏移量的线程,以防止在同一时间初始化。

        6
  •  0
  •   Ray    16 年前

    至于你最初的问题,由于Ticks很长,以下陈述:

    (int)DateTime.Now.Ticks
    

    将导致溢出。不知道那时会发生什么样的肮脏。..

    推荐文章