Vb.net 刻度不一致且波动
我有一个潜艇和一个按钮。代码是这样的:Vb.net 刻度不一致且波动,vb.net,visual-studio,debugging,time,stopwatch,Vb.net,Visual Studio,Debugging,Time,Stopwatch,我有一个潜艇和一个按钮。代码是这样的: Private Sub plus(ByRef a As Integer) For i = 0 To a a = a + a Next End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim i As Integer = 19
Private Sub plus(ByRef a As Integer)
For i = 0 To a
a = a + a
Next
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim i As Integer = 19
Dim sw As New Stopwatch
sw.Start()
plus(i)
sw.Stop()
MsgBox(sw.ElapsedTicks)
End Sub
当我运行sub时,点击“按钮1”,程序输出310,这意味着310是sw.elapsedticks
当我再次单击“按钮1”再次运行sub时,要输出1秒表的程序将退回到使用
DateTime
类,如果您的硬件不支持高性能计数器,则使用刻度进行测量。现在的大多数计算机,至少在Windows 2000及更高版本中,都有高性能计数器。考虑到这一点,.NET秒表
类基于此高频计时器。通常,调用Start
查询性能计数器并存储值。当您停止时,它会再次查询性能计数器。然后,经过的时间是这两个值的简单减法,以获得ElapsedTicks
以下是一些需要进一步解释的项目…
此属性只调用了GetRawElapsedTicks()
下面的函数返回从秒表启动到调用stopwatchStop
方法所经过的实际时间。如上所述,经过的时间是这两个值的简单减法
您可以看到以下内容:currentTimeStamp-startTimeStamp
// Get the elapsed ticks.
#if FEATURE_NETCORE
public long GetRawElapsedTicks() {
#else
private long GetRawElapsedTicks() {
#endif
long timeElapsed = elapsed;
if( isRunning) {
// If the StopWatch is running, add elapsed time since
// the Stopwatch is started last time.
long currentTimeStamp = GetTimestamp();
long elapsedUntilNow = currentTimeStamp - startTimeStamp;
timeElapsed += elapsedUntilNow;
}
return timeElapsed;
}
您可能会注意到上面的#if功能_NETCORE
,并想知道它是什么。这些命令称为预处理器命令。基本上,它们的工作方式类似于if-else
语句,但如果不满足条件,则不会在编译时包含代码,因为这是预编译决定,而不是运行时
综上所述,Hans Passant已经提到了JIT编译。我上面提到的所有这些都将其进一步分解以进行解释。差异的真正原因是它第一次编译和运行所花的时间
还有一件事要提。stopwatch
类使用一个long
变量类型来存储他们所称的frequency
。频率”存储高分辨率性能计数器的频率(如果存在),否则将存储TicksPerSecond。在系统运行时,频率无法更改,因此仅初始化一次。
下面是其他的常数
,它们与频率及其计算方式有很大关系
private const long TicksPerMillisecond = 10000;
private const long TicksPerSecond = TicksPerMillisecond * 1000;
当您创建一个新的StopWatch
类实例时,这就是所运行的
bool succeeded = SafeNativeMethods.QueryPerformanceFrequency(out Frequency);
if(!succeeded) {
IsHighResolution = false;
Frequency = TicksPerSecond;
tickFrequency = 1;
}
else {
IsHighResolution = true;
tickFrequency = TicksPerSecond;
tickFrequency /= Frequency;
}
正如您现在所看到的,频率在设置运行时间的计算方式以及勾选频率方面起着重要作用。即使在停止应用程序时,也无所谓,因为此时存储了频率。重置频率的唯一方法是重新启动m机器。我假设原因与
快速排序
方法中的代码有关。真的吗?我在新项目vb.net中再次测试,并制作了非常简单的sub。同样的问题也发生了!!当我调用sub确定时,需要200个刻度,因为sub非常简单。当我再次调用该sub时,只需要3个刻度。然后编辑你的q包含非常简单的sub。事实上,它缺少回答问题所需的功能。我猜它与CPU缓存有关。这是一篇很棒的文章。对于我们的案例,尤其是后台部分。在方法开始运行之前,必须首先从程序集中的MSIL及时编译到ma处理器可以执行的中文代码。这种情况只发生一次,即您第一次调用该方法时。您可以看到抖动完成该任务所需的时间。使用提前编译器(Ngen.exe)进行实验看到差异。所有这些关于频率的问题与这个问题有什么关系?他不是问秒表类是如何工作的,他是问为什么他在连续调用一个方法时看到时间的差异。这里唯一一段真正回答这个问题的是你提到Hans评论的那一段。@CodyGray it h这和问题有很大关系。这不仅仅是该方法第一次运行。它使用的是它第一次运行时存储的频率。我在我的帖子中解释了这一点。如果你读了最后一部分,我会解释这一点。你自己试试,第一次实例化该类时,它会存储频率。在运行相同的t时间大大缩短。方法单击一次并不重要。您可以停止应用程序并再次运行,结果仍然较低!原因是它查看存储的频率!哦,我明白您的意思。在Stopwatch类实例的第一次创建时,它的静态构造函数必须运行,这不需要花费时间这是真的(事实上,C#中的静态构造函数非常慢,因为编译器没有很好地优化它们),但此初始化不会影响定时测量,因为在调用start
函数之前不会记录启动时间。他的代码只测量start
和Stop
之间经过的时间(这实际上是调用函数plus
所需的时间)。是的,如果你在重新启动的机器上运行,你会得到非常高的滴答数。之后的任何操作都基于当前频率。查找它,获取时间戳。它在Microsoft的引用中。我发布的第一个块对此进行了调用…至少新机器支持高频率的旧机器代码到达日期我……我们很幸运;)
bool succeeded = SafeNativeMethods.QueryPerformanceFrequency(out Frequency);
if(!succeeded) {
IsHighResolution = false;
Frequency = TicksPerSecond;
tickFrequency = 1;
}
else {
IsHighResolution = true;
tickFrequency = TicksPerSecond;
tickFrequency /= Frequency;
}