2016-07-08 2 views
1

Это пример программа, я обнаружил, что позволит вам переключать некоторые действия цикла:Как работает асинхронное выполнение 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? 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, кажется, правильно останавливает цикл, даже когда он работает.

Может кто-нибудь объяснить мне, как потоки выполняются в autohotkey? Как он обрабатывает несколько блоков кода без условий гонки? Вызывает ли вызов SetTimer какую-либо роль в этом?

+1

Не знаю, почему вы спрашиваете, не глядя на документацию: [резьб подробно] (https://autohotkey.com/docs/misc/Threads.htm) , [SetTimer] (https://autohotkey.com/docs/commands/SetTimer.htm) отрицательный тайм-аут. – wOxxOm

+0

@wOxxOm Я использовал Google. Я не буду ходить через документы по страницам - у меня нет времени на это, и нет ничего плохого в вопросе вопроса, даже если ответ находится где-то в другом месте. Может быть, прочитайте справочный центр, если вы не уверены. –

+0

Требуется меньше 1 минуты, чтобы открыть документацию и выполнить поиск 'thread' и еще 1 минуту для' SetTimer'. Проводка вопроса заняла больше времени. Вот что заставило меня задуматься. – wOxxOm

ответ

3

TLDR: Темы могут прерывать друг друга.

Посмотрите на AHK docs on Threads:

Хотя AutoHotkey фактически не использовать несколько потоков, это имитирует некоторые из такого поведения: Если запускается второй поток - такой как нажатие другая горячая клавиша, в то время как предыдущая все еще работает - текущий поток будет прерван (временно остановлен), чтобы дать новый поток, чтобы стать текущим. Если третий поток запущен, а второй по-прежнему работает, то второй и первый будут находиться в состоянии покоя и т. Д.

Новая тема по сравнению с текущим потоком

Таким образом, в вашем примере, если F12 нажимается и toggle является false, он будет работать loop подпрограмму немедленно и только один раз (Период -1). Подпрограмма будет зацикливаться до тех пор, пока toggle не станет снова false.
Приходит трюк: если вы снова нажмете F12, запускается другой поток, а новые потоки по умолчанию прерывают текущий поток. Таким образом, новый поток остановит цикл, установите toggle на false, а затем закончите изящно, так как подпрограмме «горячие клавиши» нечего делать. После того, как подпрограмма «горячие клавиши» закончена, предыдущий поток (который является нашим таймером loop) возвращается к жизни. Поскольку toggle теперь false, он вырвется из цикла, а также закончит ... и, таким образом, круг будет завершен. Имейте в виду, что loop было приказано запускать только один раз, так что повторения там не было.

приоритеты темы

Новые потоки могут только прервать текущий поток, если их priority по меньшей мере равен приоритету текущего потока. По умолчанию каждый поток имеет приоритет 0, и не имеет значения, является ли это потоком Hotkey, подпрограммой с таймированием или любым другим видом потока. Конечно, есть исключение ...

Использования Sleep

AHK docs on Sleep говорит:

Во время сна, новые потоки могут запускаться через горячие клавиши, Пользовательское меню пункта, или таймер.

Если поток спит, он в основном прерывается и освобождает все время CPU для любого другого потока (только за время, что он на самом деле спит). То есть даже потоки с более низким приоритетом могут работать, пока текущий поток спал. В вашем примере есть существенный Sleep из 700 мс. Конечно, даже без сна ваш скрипт будет работать, и toggle все равно будет toggleable. Но даже если бы loop был вызван с более высоким приоритетом, хоки все равно мог бы работать, пока loop спал (что практически в большинстве случаев).

Пример кода воняет

Код примера вы вывесили может работать, но ИМО, сбивает с толку и откровенно плохое кодирование. Основная цель таймеров - периодически запускать, но здесь у нас есть цикл внутри таймера, который не соответствует цели таймеров. Если мы позволяем Hotkey нереститься более одного потока, мы могли бы даже использовать эту абсурдную, но рабочий кусок кода:

; 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 
1

Не считайте это полным ответом.
Я бы хотел добавить, что с v1.1.20 вы должны почти всегда использовать функции вместо меток. Это позволяет избежать множества потенциальных конфликтов (метки выполняются в глобальной области).
Так предпочтительно вы могли бы сделать это следующим образом:

F12:: 
__F12() { 
    Static toggle := False 
    toggle := !toggle 
    SetTimer, DoLeftClick, % toggle ? 700 : "Off" 
} 

DoLeftClick() { 
    Click 
} 
Смежные вопросы