Windows / C#系统级序号生成器?

时间:2009-04-14 14:07:56

标签: c# sequence sequential-number

是否有托管系统级序号生成器? DateTime.Now.Ticks不会这样做,因为我正在做的操作有时每次打勾都会发生多次。


要求澄清:

  • 流程不可知 - 实际上只有一个流程可以访问它。
  • 表现至关重要!这用于记录广告服务器上的展示次数,可达到1k / sec

它必须是以下之一:

  • 重置每个刻度的4字节序号
  • 一个12字节的序列号 - 基本上为DateTime增加了4个字节的粒度

7 个答案:

答案 0 :(得分:6)

没有用于此目的,但您可以使用System.Diagnostics.PerformanceCounter。您也可以使用注册表,但是您需要在整个过程中序列化读/写访问。

System.Diagnostics.PerformanceCounter pc 
    = new System.Diagnostics.PerformanceCounter("SeqCounter", "SeqInstance");
long myVal=pc.Increment();

修改

我想的越多,我认为这可能是一个很好的解决方案。增量将通过原子操作将计数器增加1,原子操作应该在系统的所有进程中起作用。

修改

根据您的修改,我不建议使用性能计数器。性能计数器是跨多个进程协调的一种方式。我不确定内部实现是如何编码的。

为什么不能只使用静态变量并递增它?如果你想让它成为线程安全的话,你将不得不锁定一些东西。

System.Threading.Interlocked.Increment

仅供参考:如果你在32位系统上使用长版本,它将不会是线程安全的。


编辑以显示我使用的实施(DS):

public static class Int32Sequencer
{
    private static Int32 lastSequence = Int32.MinValue;
    private static Object lockObject = new Object();
    public static Int32 GetNextSequence()
    {
        lock (lockObject)
        {
            unchecked { lastSequence++; }
            return lastSequence;
        }
    }
}

答案 1 :(得分:1)

Guid就像你将要获得的那样接近,但那些是“独特的”而不一定是连续的。如果您真的希望在系统级别跨多个进程进行顺序,那么您可能需要自己动手。

编辑:

好的,从你的新要求来看,我将假设:

  1. 只有一个流程需要完成工作
  2. 您要附加到数据库
  3. 所以这就是我的建议:

    1. 在流程启动时,查询DB以获取最后一个(最大)值(如果不存在则为0)。
    2. 对每个数据库行使用一个简单的long和increment。由于您的数据速率很高,您将希望批量插入。
    3. 应该这样做。把事情简单化。这没有锁定,启动时轻微(可忽略不计)命中,以及数据库中的序列号。只要你只有一个进程运行它,这个算法也是流程敏捷的。

答案 2 :(得分:0)

我认为最接近的是一个guid,我确信你知道的只是部分顺序。

答案 3 :(得分:0)

我认为我们需要更多地了解您的需求。你能澄清一下你的问题吗?特别是服务......

  • 需要跨所有流程,一个流程或特定用户工作吗?
  • 数字必须是唯一的还是只是顺序的?

根据您的问题,您可能会找到几个不同的项目。

需要系统上所有进程的连续数字组

AFAIK,不存在此类服务。一个应该相当容易编写,但让它在所有进程中工作是棘手的。

需要在系统上的所有进程中使用唯一的连续数字组

第一个问题略有不同。这样的服务不存在,因为它无法实现。使用内置数据类型无法保证唯一的序列号,因为该值最终会溢出并留下重复的数字。

需要一种在系统中获取唯一值的方法

正如其他几位用户所提到的,最好的选择是System.Guid实例。您可以使用Guid.NewGuid()创建一个新的。对于几乎所有目的,它们都可以被认为是独特的,但不是连续的。

答案 4 :(得分:0)

这里有一篇文章给出了sql server的一些细节: Sequential GUID's in SQL Server此技术用于最小化由于GUID的随机性导致的页面拆分。也许这个链接会给你一些提示或想法。

答案 5 :(得分:0)

我喜欢数据库选项只是为了安全。确保在服务器之间安装了具有足够内存的怪物SQL服务器。类似于此的系统是在我曾经工作的第一家公司(在我成为程序员之前)实施的,而且非常狡猾。你可以争取扩大规模。

另一种选择是在你的代码中实现单例函数...假设只有一个应用程序域将调用它。可能比数据库之旅快一点。但是,无论如何你要将这些东西记录到数据库中......如何将两者结合起来......运行单例速度,然后在资源允许时写入数据库。

同样,如果顺序要求不那么强,那么Guid将是你最好的选择。

答案 6 :(得分:0)

没有锁定就无法获得单个序列系列。无论你使用什么机制来分配下一个值 - 一个性能计数器,一个静态变量,无论如何 - 当两个线程同时需要下一个值时,一个必须等​​待另一个。

我要做的第一件事就是编写一个测试程序,它产生了大量的线程,每个线程都反复调用一个锁定增量函数,比如Daniel Schaffer发布的那个。这样您就可以找到应用程序开始崩溃的阈值 - 在Monitor.Enter等待的时间比在其他任何地方等待的时间长。

如果事实证明是一个问题 - 我敢打赌,如果你所谈论的卷是真实的,它会 - 然后你应该让每个线程都维护自己的顺序计数器,你可以通过标记来做带有ThreadStaticAttribute的计数器字段。然后,您可以从线程ID和计数器的组合生成唯一标识符。

如果您没有使用线程池,则此方法将无法工作(因为计数器在其所属的线程执行时会死亡)。并且您可能还希望使应用程序的启动计数成为复合ID的一部分,这样您就不必将线程计数器写入持久存储。 (如果你没有这样做,当你重新启动服务器时,线程将再次开始生成计数器为零,如果你的应用程序创建了一个与早期实例具有相同ID的线程,你将获得重复的标识符。)

这显然不是一件容易的事情(或者更重要的是,测试),所以我绝对建议首先证明它是必要的。