是否有托管系统级序号生成器? DateTime.Now.Ticks不会这样做,因为我正在做的操作有时每次打勾都会发生多次。
要求澄清:
它必须是以下之一:
答案 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就像你将要获得的那样接近,但那些是“独特的”而不一定是连续的。如果您真的希望在系统级别跨多个进程进行顺序,那么您可能需要自己动手。
编辑:
好的,从你的新要求来看,我将假设:
所以这就是我的建议:
应该这样做。把事情简单化。这没有锁定,启动时轻微(可忽略不计)命中,以及数据库中的序列号。只要你只有一个进程运行它,这个算法也是流程敏捷的。
答案 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的线程,你将获得重复的标识符。)
这显然不是一件容易的事情(或者更重要的是,测试),所以我绝对建议首先证明它是必要的。