【问题标题】:Is this JS Unique ID Generator Unreliable? (Getting collisions)这个 JS 唯一 ID 生成器不可靠吗? (发生碰撞)
【发布时间】:2018-01-15 22:29:55
【问题描述】:

我正在使用以下 JS 函数来生成唯一 ID,这是我从另一个 StackOverflow 线程获得的:

function generateUniqueID() {
    return Math.round(new Date().getTime() + (Math.random() * 100));
}

我看到它结合了当前的日期/时间和一个额外的随机器。

尽管如此,我证实我在快速添加具有 ID 的项目的每 4 次或 5 次操作中都会发生冲突。

在 JS 循环中调用该函数以从当前元素列表中生成 ID。

    jQuery.each(mainEvents, function(index, item) {
        // ...
        // Generate gaps
        gapEvents.push({"gapEventID" : "event-GAP" + generateUniqueID(), 
                                "other" : other });        
}

这个功能不可靠吗?是否允许在快速 JS 循环迭代中发生冲突?

我几乎排除了“外部原因”(即这个函数不是罪魁祸首,但可能是其他原因),但如果是这样的话,我不明白为什么 Math.random() 不会保留我很安全。

【问题讨论】:

  • 确实。我在一个 10000 项数组上尝试过。当我从该数组创建一个集合时,它只保留了 10000 个值中的大约 119 个
  • 但是为什么它不起作用?当然,这些是伪随机数,但我们仍然不希望碰撞像这样频繁吗?
  • 日期可能没有帮助,它循环执行的速度非常快,每个项目的值可能应该相同。不知道为什么 20% 的 id 会一直相同,但我希望至少有 1% 是相同的。不过,如果您想推出自己的功能,可以使用 ES6 Set 轻松跟踪唯一 ID。

标签: javascript random


【解决方案1】:

非常喜欢。您可以使用new Date().getTime() 来获取唯一的 id,假设每次迭代花费的时间超过 1 毫秒。从您的数据中可以看出,这是错误的。结合使用Math.floor的RNG,很有可能得到重复值。只要间隔小于 1 毫秒,您就会得到重复次数。如果您想要基于 RNG 概念的唯一 ID,我会说只使用 Math.random() 到 10^15 是更好的选择。 10^15 是永远不会超过Number.MAX_SAFE_INTEGER 的最大整数位长度。

Math.floor(Math.random() * Math.pow(10, 15))

【讨论】:

    【解决方案2】:

    这个功能不可靠吗?

    在我看来确实如此。

    事实上,new Date().getTime() 是一个每毫秒增加 1 的整数,而Math.random() * 100 是一个伪随机数,它给出了一个介于 0 到 99 之间的数字。

    所以如果函数被快速调用多次,它们的总和可能真的会经常重复。

    想想如果函数每毫秒被调用两次,它很可能有两次相同的数字。它有 1/100 的概率发生(考虑到我使用该函数在大约 1 秒内生成了 10.000 个 id 的列表并获得约 100 个重复项,这几乎是我得到的结果,这与数量级)

    【讨论】:

      【解决方案3】:

      以下根据回复比较建议的方法。

      但我认为我的需求方向错了。我将在服务器端使用 ID/Sequence 来确保唯一性。

      function run() {
      var nums1 = new Set(), nums2 = new Set(), nums3 = new Set();
      
      for (var i = 0; i < 10000; i++) {
         nums1.add(originalMethod());
      }
      for (var i = 0; i < 10000; i++) {
         nums2.add(concatMethod());
      }
      for (var i = 0; i < 10000; i++) {
         nums3.add(random10To18thMethod());
      }
      console.clear();
      console.log('Original Method set: ' + nums1.size);
      console.log('Concat Method set: ' + nums2.size);
      console.log('Math.Random 10^18 set: ' + nums3.size);
      function originalMethod() {
         return Math.round(new Date().getTime() + (Math.random() * 100));
      }
      
      function concatMethod() {
         return Math.round(new Date().getTime() + '' + (Math.random() * 100));
      }
      function random10To18thMethod() {
         return Math.random() * Math.pow(10, 18);
      }
      }
      &lt;button onclick="run()"&gt;Run Algorithms&lt;/button&gt;

      【讨论】:

        【解决方案4】:

        随机值是never 一个唯一值。即使有时间戳,您也不能保证结果是 100% 唯一的。但是,您可以通过生成更大的(随机)值来最小化这种情况。

        但是,使用时间戳,当同时有多个推送时,您会覆盖自己。使用额外的随机数将创建一个几乎唯一的值,在大多数用例中是唯一的。

        我建议虽然使该随机值更长。或者创建一个 GUID。

        Create GUID / UUID in JavaScript?

        【讨论】:

        • 但是根据您的评论,我应该几乎总是被时间戳+随机(0..100)所覆盖,对吧?那么为什么碰撞如此频繁,如每 6 次或 8 次操作,而不是每 10,000 次?为了使值更长,我应该使用 Math.random() * 1000000 而不是 * 100?
        • 我认为碰撞问题是由于将随机添加到时间作为数字 (1+1=2) 引起的。尝试这样做:console.log( Math.round(new Date().getTime() + '' + (Math.random() * 100)));
        猜你喜欢
        • 1970-01-01
        • 2012-05-20
        • 2011-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-26
        • 1970-01-01
        相关资源
        最近更新 更多