【问题标题】:How can I performantly assign unique Ids to objects in C#如何在 C# 中高效地为对象分配唯一 ID
【发布时间】:2023-03-13 20:00:01
【问题描述】:

我正在开发一个 C# 库,它将创建大量小对象作为正常操作的一部分(想想编译器中的 AST 节点)。我想以不会影响性能的方式为每个实例分配一个唯一标识符(在程序中是唯一的,而不是全局唯一的)。对象是不可变的,并且可以跨线程共享,因此 id 需要跨线程唯一。

以下是我正在考虑的一些选项:

  1. 使用静态 int 或 long,并通过调用 Interlocked.Increment() 获取每个新 id
  2. 使用Guid.NewGuid()生成id
  3. 使用带有[ThreadStatic] 属性的静态int 或long 字段,然后从当前线程的ManagedThreadId 属性和线程本地计数器的下一个值生成字符串id。

其中一个会比其他的性能更好吗?有没有更好的方法来做到这一点?

谢谢!

编辑:
我运行了一个快速基准测试并得到以下结果:

  1. 0.19 秒(int 与 long 基本相同)
  2. 1.1 秒
  3. 3.5 秒

这似乎强烈指向使用Interlocked。但是,Interlocked 在多线程场景中是否有变慢的风险?

【问题讨论】:

  • 在我看来,您的 (1) 是迄今为止解决您提出的问题的最佳方法。 Interlocked.Increment() 是超快的。只要您生成的数量不超过 2^31 个。 ;)
  • 我一直使用 CombGuids - 它们基于当前日期/时间,因此除非您的代码每秒产生数千个 id - 几乎不可能发生冲突。有关代码,请参阅此帖子。 stackoverflow.com/questions/665417/…
  • @Jay:嗯,对于只需要在一个程序上的特定运行时唯一的东西来说,这是一个很大的开销。
  • 选项1. 既然不需要全局,guid就是浪费资源
  • @MatthewWatson - 看起来很慢,但还不错。在我的机器上,生成一百万个 guid 需要 0.1 秒,生成 100 万个 CombGuid 需要 1 秒。所以它比生成 Guid 慢了大约 10 倍,但它很有用,因为它们几乎肯定是独一无二的。只是把它作为一种选择扔出去!

标签: c# guid thread-local unique-id interlocked-increment


【解决方案1】:

Interlocked.Increment 的工作原理是确保对++ 的调用作为原子操作发生。这意味着另一个线程无法获取中间变量,这可能使用++

唯一的性能问题是需要同步存储变量的内存,请注意,此性能成本应该可以忽略不计,正如您的测试所显示的那样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 2022-07-15
    • 1970-01-01
    • 1970-01-01
    • 2019-03-30
    • 1970-01-01
    相关资源
    最近更新 更多