代码之家  ›  专栏  ›  技术社区  ›  Pure.Krome

从现在到以前的某个时间点(如1小时前),我如何得到一个随机时间?

  •  5
  • Pure.Krome  · 技术社区  · 15 年前

    我正在尝试创建一个扩展方法,它允许我创建一个从现在到某个用户请求的历史时间点之间的随机时间(以时间跨度的形式)。

    例如: 从现在到一小时前的随机时间。

    所以,我想到了 Random(..) 扩展方法。

    我想让随机种子不是静态的,但是如果我经常快速地调用这个方法(例如在循环中),那么我认为种子(基于时间)对于非常快速的调用来说并不是真正随机的。是真的吗?(当我检查结果时,似乎是这样)

    public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
    {
        var random = new Random();
        DateTimeOffset minDateTime = value.Subtract(timeSpan);
        int range = ((DateTime.Today - minDateTime)).Hours;
        return minDateTime.AddHours(random.Next(range));
    }
    
    3 回复  |  直到 15 年前
        1
  •  9
  •   Jon Skeet    15 年前

    正如其他人所说,问题是 new Random() 使用当前时间来形成种子,并且您多次获得相同的种子。

    基本上你想要创建相对较少的实例。AS Random 不是线程安全的,你需要 ThreadStatic ThreadLocal<T> -后者是.net 4.0的新版本。这是一个样品 StaticRandom 类(使用.net 4.0),它允许您使用 Instance 属性获取此线程的有效实例。注意,在类型初始化时,计数器是从当前时间设置的。然后用于连续的种子。

    using System;
    using System.Threading;
    
    public static class StaticRandom
    {
        private static int seed;
    
        private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
            (() => new Random(Interlocked.Increment(ref seed)));
    
        static StaticRandom()
        {
            seed = Environment.TickCount;
        }
    
        public static Random Instance { get { return threadLocal.Value; } }
    }
    

    那你就可以用 StaticRandom.Instance 每当你需要一个 随机的 .

    现在回到最初的问题,现在还不完全清楚您当前的扩展方法在做什么。你为什么要用 DateTime.Today 完全?我想你想要这样的东西:

    public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
    {
        double seconds = timeSpan.TotalSeconds * StaticRandom.Instance.NextDouble();
    
        // Alternatively: return value.AddSeconds(-seconds);
        TimeSpan span = TimeSpan.FromSeconds(seconds);
        return value - span;
    }
    

    不过,这会给你一个 完全地 随机时间——比如说,它几乎肯定是一毫秒的一部分。这样可以吗,或者你真的希望它是一个精确的秒数(或分钟,或小时)的基础上,原来的时间跨度?

        2
  •  7
  •   Pure.Krome    15 年前

    使用A Random 创建/初始化的对象 一旦 每次调用方法时。另一个选择是通过 随机的 在调用方法时将实例放入该方法。

    您还可以创建允许您执行上述任一选项的重载:

    public static DateTimeOffset Random(this DateTimeOffset value, TimeSpan timeSpan)
    {
        if (_threadStaticRng == null)
            _threadStaticRng = new Random();
    
        return value.Random(timeSpan, _threadStaticRng);
    }
    
    public static DateTimeOffset Random(
        this DateTimeOffset value, TimeSpan timeSpan, Random rng)
    {
        DateTimeOffset minDateTime = value.Subtract(timeSpan);
        int range = ((DateTime.Today - minDateTime)).Hours;
        return minDateTime.AddHours(rng.Next(range));
    }
    
    [ThreadStatic]
    private static Random _threadStaticRng;
    
        3
  •  -1
  •   Adam Gritt    15 年前

    你必须给随机数生成器播种子。一个好的做法是:

    var random = new Random((int)DateTime.Now.Ticks);
    

    这应该会让你更随意。

    还可以将随机生成器创建为静态类变量,这样就不必每次都实例化它。