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是用来建立一个有用的问题和答案数据库的。下次有人用谷歌搜索这个特定的问题时,他可能会发现这个。