多线程与单线程的区别:
单线程顺序执行:ABCDEFG,HIJKLMN
单线程异步执行:ABC,KLMN,EFGHI,错开执行避免I/O之类的长时间等待卡住线程【WinWait】
多线程:一个进程内可有多个线程ABCDEFG同时执行互不干扰
多进程:创建多个进程ABCDEFG并互相通信,来达到仿多线程的效果。
以下都是用异步执行来防止线程阻塞的示例方法
1、递归+异步执行
SetBatchLines -1
Gosub 异步执行
; 下面这个Loop循环会阻塞线程,但异步执行仍然可以工作
Loop {
Sleep 10
ToolTip 主线程持续运算演示-%A_Index%
} Return
异步执行:
Run Notepad,, Min, PID
; 这步等效于 WinWait 【等待直到指定的窗口存在】
异步执行2:
if WinExist("ahk_pid " PID)
Goto 异步执行3
SetTimer 异步执行2, -10
Return
; 这步等效于 Sleep 3000 【延时3秒】,后台往记事本里写入"Sleep 3000 WinActivate",并在3秒后激活记事本窗口
异步执行3:
ControlSend, Edit1, "Sleep 3000 WinActivate", ahk_pid %PID%
SetTimer 异步执行4, -3000
Return
异步执行4:
WinActivate, ahk_pid %PID%
Return
2、异步监测函数封装
; Lexikos对SetTimer延时的解释:https://www.autohotkey.com/boards/viewtopic.php?f=76&p=190621
; 总结:SetTimer操作20ms以上的等待任务才具备性价比,建议使用默认的周期 -100
#Persistent
Global t1:=A_TickCount
AsynchronousFunc("ahk_class Notepad", 100) ; 10秒内监测记事本窗口是否存在,超时后退出脚本
Loop
ToolTip 主线程持续运算演示-%A_Index%
Return
AsynchronousFunc(WinTitle, Loop:=0) {
Static Count := 0
; 当记事本窗口存在时,异步监测立即停止
(WinExist(WinTitle) && Count := Loop-1)
if (++Count!=Loop) {
SetTimer %L%, % -100+6 L:=Func(A_ThisFunc).Bind(WinTitle, Loop) ; Bind()保持与函数参数相同
Return True
}
ifWinExist, %WinTitle%,, MsgBox % "异步耗时仅做大致判断:`n`n等待耗时:" A_TickCount-t1 " 毫秒"
ExitApp
Return False
}
3、递归循环计数后中止计时【示例为60次】
SetBatchLines -1
a=1
SetTimer 递归循环, 100
Loop {
Sleep 100
MouseGetPos, x, y
ToolTip, 主线程持续运算演示-%A_Index%, x+10,y-80
} Return
递归循环:
ToolTip % "递归调用异步执行-" a++
if (a= 60)
SetTimer 递归循环, off
Return
4、异步监控变量变化
SetBatchLines -1
a := 1 , b := a
SetTimer 异步监控变量变化, 1
Loop {
Sleep 10
ToolTip, 主线程持续运算演示-%A_Index%
} return
异步监控变量变化:
if (a!=b) {
SoundPlay *-1 ; 以系统提示音为提示变量以变化
b := a
; SetTimer 异步监控变量变化, off
} return
F1::a := 2
F2::a := 3
优秀、神秘、完美!
学习中