如果DateTime.Now不够好怎么办?

时间:2013-07-05 07:43:46

标签: c# datetime cqrs event-sourcing event-store

好的,这就是问题所在。我们正在使用CQRS和Event Sourcing,我们正在使用聚合实例的每个提交序列的事件流。并且每个流都会随着它的创建日期而持续存在,但事实是所有这些都发生得太快,这意味着某些聚合事件流(某些流程(注册,通知等)的一部分)会出现与完全相同的日期。因此,当我们必须重放事件时,按创建日期排序流不起作用beacouse有事件流依赖于时间,但它们发生得如此之快以至于看起来它们发生并行(意味着我们使用DateTime.UtcNow和日期等于纳秒)。

对于那些不知道CQRS或事件采购是什么的人

想象一下,您有一个资源列表,每个项目都有其创建日期。 并且知道列表中项目的创建顺序至关重要。请记住,在列表中有多个线程创建和添加项目。问题是,当一个线程必须在列表中创建并添加两个项目时,它们的创建日期匹配你不能正确地按日期排序它们。顺便说一句,我的电脑上的电脑很重要DateTime.Now不等于服务器上的DateTime.Now。实际上在一个同事上加载了25000次DateTime.Now到列表结果列表的第一个和最后一个元素等于纳秒(完全匹配)

2 个答案:

答案 0 :(得分:2)

时间戳是一段有用的元数据。它不是 - 正如您所发现的 - 可靠的订购标准。想象一下,你在你的机器上提出了一些解决方案,但现在必须使用两台机器?你能让他们的时钟在一纳秒内保持同步吗?少?

在事件采购中,典型的保证仅是事件在单个流中排序,例如,一个聚合。无论如何,这是您的交易保证。为什么不使用整数来跟踪流中的每个事件的序列?您的聚合可以生成它,因为它一直在跟踪所有事件。

如果您想跨流进行排序,则必须集中生成该序列号(使用表示的耦合),或者接受多个流的多次读取并不总是以相同的顺序返回事件,只是事件应该对一个流中的内容进行排序。

答案 1 :(得分:1)

您可以通过调用Windows API的QueryPerformanceCounter()获得一个准确的数字,您可以将其用作时间戳, 应该在具有高分辨率的线程之间为您提供一致的值。

当然,这只会为您提供与某台特定计算机相关的值;如果要比较在两台不同计算机上创建的时间戳,则无法使用它。

但请注意这一点(来自Windows API文档):

  
    

在多处理器计算机上,调用哪个处理器无关紧要。但是,由于基本输入/输出系统(BIOS)或硬件抽象层(HAL)中的错误,您可以在不同的处理器上获得不同的结果。

  

(我自己没有在任何硬件上遇到过上述错误。)

您可以通过C#进入性能计数器,如下所示:

public long PerformanceCounter()
{
    long result;
    QueryPerformanceCounter(out result);
    return result;
}

[DllImport("kernel32.dll", SetLastError=true)]
static extern bool QueryPerformanceCounter(out long lpPerformanceCount);