2

我们有一个(非常)用 VB6(15 岁?)编写的旧版应用程序。

该应用程序包含一个间隔为 300 毫秒的计时器。当计时器计时时调用的 Sub 执行一批与一些 SQL 服务器对话的代码,打印一些标签等等。

当一切正常时,这个 Sub 在 5ms 到 10ms 内执行 - 即在下一个计时器间隔发生之前 - 但它也在下一个滴答声之前浪费了 290ms。

我们需要让这个应用程序更快一点,一个选择是将间隔更改为 1ms - 在我们这样做之前,我想确认计时器是否会中止间隔(又名 - 完全忽略滴答声)如果前一个间隔仍在执行 - 或者它会开始构建对子的调用堆栈,导致一段时间后挂起?(我当然假设所有滴答声都在与 gui 相同的线程中执行 - 因此我们需要在每次滴答声后使用 DoEvents 以确保 UI 不会挂起。)

我已经尝试过对此进行调查,但要找到有关旧 VB6 计时器的可靠信息证明是很棘手的。

我们确实安排了这个计划,以便使用线程和后台工作线程在 .net 中重新编写——这只是我们正在研究的一个短期修复。

4

5 回答 5

3

这不是 VB6 计时器的工作方式,Tick 事件只能在您的程序空闲并停止执行代码时触发。技术术语是“再次泵送消息循环”。DoEvents 泵送消息循环。这是一个非常危险的函数,因为它不仅调度计时器的 Tick 事件,而且调度所有事件。包括那些让用户在忙于执行时关闭窗口或再次启动功能的功能。不要使用 DoEvents 除非你喜欢危险地生活或彻底了解它的后果

您将速度提高 300 倍的追求也注定要失败。对于初学者,您无法获得 1 毫秒的计时器。Windows 上的时钟分辨率还不够高。默认情况下,它每秒递增 64 次。因此,您可以获得的最小间隔是 16 毫秒。其次,你不能指望任意让慢代码变得更快,至少因为 Tick 事件不会叠加。

您可以要求 Windows 提高时钟分辨率,它需要调用 timeBeginPeriod()。这不是你应该考虑的事情。如果这真的可行,那么当您每毫秒访问该服务器时,您一定会得到一个携带钝器的相当交叉的 dbase 管理员的访问。

于 2013-04-26T13:31:52.730 回答
2

如果计时器是一个 GUI 组件(即不是线程池计时器),并且由 WM_TIMER 'messages' 触发,则 'OnTimer' 事件不能'stack up'。WM_TIMER 实际上并没有排队到 Windows 消息队列,它是在主线程返回到消息队列并且计时器间隔已到期时合成的。

于 2013-04-26T11:48:51.040 回答
1

当一切正常时,这个 Sub 在 5ms 到 10ms 内执行 - 即在下一个计时器间隔发生之前 - 但它也在下一个滴答声之前浪费了 290ms。

如果时间间隔为 300 毫秒,这正是您设置的。它不会浪费 290 毫秒,它会等到 300 毫秒之后再触发 Tick 事件。

如果您希望它更频繁地执行,则将时间间隔设置为 1ms,在 Tick 事件开始时停止计时器,并在完成处理后重新启动它。这样,操作之间将只有 1ms 的空闲时间。

于 2013-05-07T14:58:39.563 回答
0

如果你把你的定时器间隔设置得比你的执行时间快,这个锁可能会让你在VB6中尽可能快地执行你的代码。

Private isRunning As Boolean

Private Sub Timer1_Tick()
    If Not isRunning Then
        isRunning = True
        'do stuff
        isRunning = False ' make sure this is set even in the event of an exception
    End If
End Sub

但是,如果您尽可能多地处于此事件处理程序中,或者尽可能快地接近 100% 的时间,您的应用程序将变得对 UI 事件响应缓慢或无响应。如果你把它放在DoEvents里面,do stuff你会给 UI 一个处理事件的机会,但是 UI 事件会在里面停止执行do stuff。想象一下移动窗口并停止执行......在这种情况下,您可能想要生成另一个线程来完成 UI 线程之外的工作,但是在 VB6 中祝您好运(我听说这并非不可能)。

于 2013-04-29T15:49:43.477 回答
0

为了最大限度地提高速度,使用一组循环指令,将计时器全部移除,并在程序入口点(Sub Main 或 Form_Load)的末尾为其调用一个函数。

在函数内,执行循环并使用 QueryPerformanceCounter 来管理重复间隔。通过这种方式,您可以消除计时器消息系统的开销,并且可以绕过计时器存在的最小计时器间隔。在循环的顶部添加一次 Doevents,以便循环以便其他事件可以触发;并在等待时消耗空闲时间。

于 2013-10-02T07:54:35.580 回答