为什么我的C#计算时间可能是不确定的?

为什么我的C#计算时间可能是不确定的?,c#,.net,C#,.net,我正在运行一个搜索算法,该算法在开始时由一个种子提供。从这一点上说,我期望算法以确定性的方式运行,这在很大程度上是如此。我可以通过观察10000步和20000步,并看到它们是相同的,来大致验证这一点。不过,我看到的不同之处是,线程处理器到达同一位置所用的时间长度(采用了相同的路径)。我正在测量线程时间 ProcessThread.TotalProcessorTime 为了量化这一点,我为您做了一些测试。我改变了运行时间,并测量了在此时间内评估的解决方案的数量 我每次重复测试8次。底部两行显示了

我正在运行一个搜索算法,该算法在开始时由一个种子提供。从这一点上说,我期望算法以确定性的方式运行,这在很大程度上是如此。我可以通过观察10000步和20000步,并看到它们是相同的,来大致验证这一点。不过,我看到的不同之处是,线程处理器到达同一位置所用的时间长度(采用了相同的路径)。我正在测量线程时间 ProcessThread.TotalProcessorTime

为了量化这一点,我为您做了一些测试。我改变了运行时间,并测量了在此时间内评估的解决方案的数量


我每次重复测试8次。底部两行显示了30秒时间内评估的平均溶液,然后是标准偏差。我重复了120秒测试,因为第一次的标准偏差很高,第二次的标准偏差要低得多

如果我的算法做相同的工作,那么什么会导致相同的工作需要不同的时间?引入了什么随机元素

要澄清几点:

  • 我说的是线程处理器时间,而不是时钟时间
  • 该算法在单个线程上运行,没有与其他线程的显式交互
  • 此环境是Windows XP.Net C#双处理器
  • 它是一个控制台应用程序
  • 算法使用处理器和内存,只有在完成后才会将结果打印到屏幕上
    向优化、内存管理(GC、分配、分页等)和即时编译致意。

    处理器时间是共享时间,因此计算机上发生的任何其他活动都可能影响性能


    我得到纠正。

    在处理器级别,缓存未命中和错误的分支预测都会影响从一次运行到另一次运行所需的处理器时间。在框架级别上,JITing和GC也会影响它。后者比前者更容易被观察到。

    您的算法使用了哪些资源?是否有其他流程使用相同的资源?这包括CPU、内存、IO(页面文件)。其他进程将对算法的性能产生影响


    时间上的差异是什么?1%? 10%?

    您的算法可能是确定性的,但绝对没有任何环境和运行时元素是:

    • 代码运行在需要分配内存的运行时上,从您的角度来看,这是不确定的
    • 从您的角度来看,运行时有一个垃圾收集器,它在不确定的时间段运行
    • 操作系统不是软实时或硬实时,因此处理器管理会影响定时
    总之,不要期望在非确定性系统中出现确定性行为。Windows CE支持硬实时,但您仍然需要在其上使用.NET以外的其他工具

    请记住,“确定性”在某种意义上是这样说的:“这段代码每次运行仅需20毫秒。在非确定性操作系统上,您不可能通过非确定性运行时实现这一点



    操作系统意义上的决定论通常没有“精确”严格,更像是:“我可以保证我在X内回复,否则我会出错。”“。在这一点上,软实时和硬实时分别越来越不灵活。

    您的进程是否有专用处理器?我猜您也没有使用实时操作系统,因此硬件中断会造成差异。您是在评估应用程序还是底层系统架构?也就是说,线程切换、缓存未命中、进程优先级等对计数器有何影响?另外,请记住海森堡原理……您的算法可能是确定性的,但是机器上同时发生的许多其他事情也会产生影响(特别是在现代操作系统中)。使处理器总时间具有确定性的唯一真正方法可能是机器上运行的唯一东西(即没有操作系统)。CLR分配内存。优化/JIT编译可能具有确定性,也就是说,除非settngs/compiler/code发生变化,否则编译器总是将代码编译成相同的样子。好吧,GC是所有代码中最不确定的,也最有可能产生影响,但由于它是一种“搜索算法”,搜索空间可能很大,我认为分页将产生很大的影响。@Adam:分配是非常快速和确定的。@Henk从未说过它不是,但它不能保证在给定的时间内做出响应-操作系统将在这里引入问题。确定性系统需要提供这些保证。不正确-处理器时间是共享的,但是
    ProcessThread.TotalProcessorTime
    计数器将只记录处理器在该线程上花费的时间。此计数器不会计算机器上发生的任何其他活动。但是,并非完全不正确。一个活动上的物理处理器时间可能保持不变,但由于处理器正在更改任务,从开始到结束的时间会导致确定性行为。@Adam您的意思是由于上下文切换?不仅如此,还包括给处理器执行某个任务的时间片,在运行多个进程的普通操作系统上,从应用程序的角度来看,时间片是不确定的。很容易将其扩展到有能力的硬件领域,但OP已经声明了.NET而没有声明任何硬件,因此我假设Windows桌面。缓存未命中和错误的分支预测也可能是确定性的,但是也会有操作系统级别的方面(例如内存分配和线程被抢占时)这也会产生影响。GC点听起来不错,但是第一个和第三个项目是错误的,或者至少是有争议的。第三个项目不是有争议的,是吗
        30s         60s          120s        120s
    473,962     948,800     1,890,668   1,961,532
    477,287     954,335     1,888,955   1,936,974
    473,441     953,049     1,895,727   1,960,875
    475,606     953,576     1,905,271   1,941,511
    473,283     951,390     1,946,729   1,949,231
    474,846     954,307     1,840,893   1,939,160
    475,052     952,949     1,848,938   1,934,243
    476,797     957,179     1,945,426   1,951,542
    
    475,034     476,599       473,831     486,721
      1,478       2,426        23,922      11,108