Asynchronous 自动热键';什么是异步执行工作?
这是我发现的示例程序,它允许您切换一些循环操作:Asynchronous 自动热键';什么是异步执行工作?,asynchronous,autohotkey,Asynchronous,Autohotkey,这是我发现的示例程序,它允许您切换一些循环操作: ; This toggles the action toggle:=false F12:: ; If true is assigned to toggle, loop starts ; It also can assign false even when loop is running If (toggle := !toggle) SetTimer, loop, -1 return loop: ; Endless loop? Actu
; This toggles the action
toggle:=false
F12::
; If true is assigned to toggle, loop starts
; It also can assign false even when loop is running
If (toggle := !toggle)
SetTimer, loop, -1
return
loop:
; Endless loop? Actually not, the value of toggle can be changed by
; another "thread" even when this loop is running
while toggle
{
Click
Sleep, 700
}
return
现在我们可以看到有一种超时类型的调用,它启动了无休止的循环。无止境的循环显然是同步的,没有回调、同步块或任何东西
尽管如此,按F12似乎可以正确地停止循环,即使在循环运行时也是如此
有人能给我解释一下自动热键是如何执行线程的吗?它如何在没有竞争条件的情况下处理多个代码块?SetTimer
调用在此过程中起作用吗?TLDR:线程可以相互中断。
请看一下:
虽然AutoHotkey实际上不使用多线程,但它
模拟其中一些行为:如果启动了第二个线程,例如
当上一个热键仍在运行时,按另一个热键--
当前线程将被中断(暂时停止)以允许
新线程将变为当前线程。如果第三个线程在
第二个仍在运行,第二个和第一个都将处于运行状态
休眠状态,等等
新线程与当前线程
因此,在您的示例中,如果按下F12
,并且toggle
为false
,它将立即运行循环
子例程,并且只运行一次(期间-1
)。子例程将循环,直到切换
再次变为假
。诀窍来了:如果再次按F12,另一个线程将运行,默认情况下,新线程将中断当前线程。因此,新线程将停止循环,将
toggle
设置为false
,然后优雅地完成,因为热键子例程已无事可做。热键子例程完成后,上一个线程(即我们的循环
计时器)恢复正常。由于toggle
现在是false
,它将打破循环并完成…因此循环完成。请注意,循环
只被命令运行一次,因此不再重复
线程优先级
如果新线程的优先级至少等于当前线程的优先级,则新线程只能中断当前线程。默认情况下,每个线程的优先级为0
,无论是热键线程、定时子例程还是任何其他类型的线程。当然,有一个例外
使用睡眠
他们说:
睡眠时,可以通过热键、自定义菜单启动新线程
项目或计时器
如果一个线程正在睡眠,它基本上会被中断,并为任何其他线程释放所有CPU时间(仅在它实际睡眠的时间内)。也就是说,即使优先级较低的线程也可以在当前线程睡眠时运行。在您的示例中,有大量的睡眠时间
为700毫秒。当然,即使没有睡眠,您的脚本也可以工作,切换
仍然可以切换。但是,即使以更高的优先级调用了loop
,hokey仍然能够在loop
处于睡眠状态时运行(这实际上是大部分时间)
示例代码很糟糕
您发布的代码示例可能有效,但在我看来,这是一个令人困惑的错误代码。计时器的主要目的是周期性地运行,但这里我们在计时器中有一个循环,这违背了计时器的全部目的。
如果我们允许热键生成多个线程,我们甚至可以使用这段荒谬但有效的代码:
; Bad example!
#MaxThreadsPerHotkey 2
toggle := false
F12::
toggle := !toggle
while(toggle) {
SoundBeep
Sleep, 500 ; Would even work without the Sleep
}
return
使用计时器完成他们的任务
下面是我如何实现切换功能,每700毫秒左键单击一次:
toggle := false
F12::
toggle := !toggle
if(toggle) {
SetTimer, DoLeftClick, Off
} else {
SetTimer, DoLeftClick, 700
}
return
DoLeftClick:
Click
return
不要认为这是一个完整的答案。 我想补充一点,从v1.1.20开始,您几乎应该始终使用函数而不是标签。这避免了许多潜在的冲突(标签在全局范围内执行)。
所以你最好这样做:
F12::
__F12() {
Static toggle := False
toggle := !toggle
SetTimer, DoLeftClick, % toggle ? 700 : "Off"
}
DoLeftClick() {
Click
}
不知道为什么不看文档就询问:,'的负超时。@wOxxOm我用过谷歌。我不会一页一页地浏览文档——我没有时间这样做,即使答案在别处,问这个问题也没什么错。如果您不确定,可以阅读帮助中心。打开文档并搜索
线程
需要不到1分钟的时间,而设置计时器
需要1分钟的时间。发布这个问题需要更多的时间。这就是我想知道的。那又怎样?StackOverflow是用来建立一个有用的问题和答案数据库的。下次有人用谷歌搜索这个特定的问题时,他可能会发现这个。