网上经常能看到一段 AHK v1 的“性能优化模板”,里面有 #NoEnvSetBatchLines, -1SendMode Input 等参数。很多人直接复制到脚本开头,但不一定知道每一行到底做了什么。

这篇主要参考并翻译整理自 AutoHotkey 英文论坛的 Optimize Your AutoHotkey Macro Scripts。原帖里的 ^NOTES 对 v1 参数解释得比较细,我这里按本站习惯重新整理成中文说明。我的看法是:这些参数可以作为参考,但不要不分场景整段套用。

一、常见优化模板

#Requires AutoHotkey v1.1
#NoEnv
#MaxHotkeysPerInterval 99000000
#HotkeyInterval 99000000
#KeyHistory 0
ListLines Off
Process, Priority,, A
SetBatchLines, -1
SetKeyDelay, -1, -1
SetMouseDelay, -1
SetDefaultMouseSpeed, 0
SetWinDelay, -1
SetControlDelay, -1
SendMode Input

这段看起来很猛,但它并不是魔法。它主要做了三类事:关闭一些调试记录、减少命令默认延迟、调整发送模式和进程优先级。

二、逐条解释

参数 作用 使用建议
#NoEnv 让未定义变量不再回退查找同名环境变量,减少歧义,也略微提升兼容性和速度。 v1 脚本建议长期保留,放在脚本开头。
#MaxHotkeysPerInterval
#HotkeyInterval
控制短时间内触发太多热键时的报警阈值。设得极大,相当于不容易弹出热键过载警告。 它不提升执行速度,只是避免宏脚本频繁触发热键时被提示。也可能掩盖死循环或误触发。
#KeyHistory 0 关闭按键历史记录,减少调试信息维护。 发布脚本可用;排查热键问题时可以临时去掉。
ListLines Off 关闭最近执行行记录,减少解释器维护调试日志的开销。 发布脚本可用;排查流程问题时再打开。
Process, Priority,, A 把当前脚本进程优先级设为 Above Normal。也有人设为 H,即 High。 一般 A 就够了。不要轻易用 Realtime,高优先级不能解决逻辑慢,还可能影响系统响应。
SetBatchLines, -1 让脚本尽可能连续执行,不按默认节奏自动短暂停顿。 对循环和批处理有用,但长循环里仍要主动 Sleep 或拆任务,否则可能占满 CPU。
SetKeyDelay, -1, -1 设置 SendEvent 模式下按键之间延迟和按住时长。-1 表示无延迟。 SendEvent 有意义;SendInput 基本不受它控制。某些游戏或旧软件反而需要一点延迟。
SetMouseDelay, -1 减少鼠标命令后的自动延迟。 适合连续点击和移动。目标软件处理慢时,保留小延迟更稳。
SetDefaultMouseSpeed, 0 MouseMove 等命令默认瞬移,而不是按速度参数平滑移动。 普通自动化常用。需要模拟人的鼠标轨迹时,不要设为 0。
SetWinDelay, -1 减少窗口命令后的自动延迟,例如 WinActivateWinMove 适合批量窗口操作;窗口响应慢时,应该用 WinWaitWinWaitActive 确认状态。
SetControlDelay, -1 减少控件命令后的自动延迟,例如 ControlClickControlSetText 控件自动化可以用,但目标程序处理慢时,应该等待控件状态,不要盲目连发。
SendMode Input 让后续 Send 默认使用 SendInput,通常速度最快。 文本输入和普通宏常用;遇到键盘钩子、游戏、远程桌面或兼容性问题时,改测 SendEventSendPlay

三、精准 Sleep 和计时器分辨率

原帖还提到通过 ZwSetTimerResolution 改变 Windows 计时器分辨率,再配合 DllCall("Sleep")ZwDelayExecution 做更细粒度等待。这类技巧在宏、游戏输入和定时测试中可能有用,但它影响的是系统级计时行为,不建议普通脚本无脑套用。

; 0.5ms 级计时器分辨率,属于系统级影响,谨慎使用
DllCall("ntdll\ZwSetTimerResolution", "Int", 5000, "Int", 1, "Int*", MyCurrentTimerResolution)

; 直接调用 Windows Sleep
DllCall("Sleep", "UInt", 16)

; 更细粒度的相对等待,-5000 约等于 0.5ms 的等待意图
delay := -5000
DllCall("ntdll\ZwDelayExecution", "Int", 0, "Int64*", delay)

这类代码的重点不是“更高级”,而是“更接近系统计时器”。如果瓶颈不是 Sleep 精度,而是图像搜索、窗口等待、磁盘 IO 或网络请求,改计时器并不能解决问题。

四、Unicode x64 与 PixelSearch Fast

原帖里还有两个小提醒值得保留。

第一,能选择 AHK 版本时,Unicode x64 通常更适合作为主力版本。现在多数 Windows 环境都是 64 位,Unicode 版本处理中文和系统 API 也更自然。

第二,PixelSearchFast 参数不一定永远更适合。如果只是搜索单个颜色、单个像素,或者搜索区域很小,加不加 Fast 最好用自己的目标场景实测。不要看到“Fast”就默认一定更快、更准。

五、真正应该优先优化什么

性能优化最怕变成“玄学清单”。我更建议按这个顺序排查:

  1. 先确认慢在哪里,是循环、找图、文件、网络、窗口等待,还是目标软件响应慢。
  2. 缩小 ImageSearch / PixelSearch 搜索区域。
  3. 减少循环里的窗口查找、文件读取、正则解析和对象创建。
  4. 需要连续执行时再用 SetBatchLines, -1
  5. 最后才考虑计时器分辨率和微优化写法。

写给自己临时用的小脚本,可以简单粗暴一点;准备长期维护或分享给别人的脚本,稳定性和可读性往往比极限速度更重要。

六、简单测速方法

不要凭感觉判断快慢。v1 里可以先用 A_TickCount 做粗略测试,需要更细时再用 QueryPerformanceCounter

start := A_TickCount

Loop, 100000
{
    ; 把要测试的代码放这里
}

MsgBox, % "耗时:" A_TickCount - start " ms"

如果两种写法只差几毫秒,而代码复杂很多,那多数情况下不值得换。优化的目的不是把代码写得吓人,而是让脚本在真实场景里更快、更稳。

相关专题

参考来源

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。