异步执行来防止线程阻塞的示例方法

多线程与单线程的区别:

单线程顺序执行: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

给TA捐赠
共{{data.count}}人
人已捐赠
其他案例

kernel32示例:实现简单的全/半角字符和简繁转换

2021-12-2 9:11:53

其他

普通权限添加开机自启动的方法

2021-12-5 11:13:16

2 条回复 A文章作者 M管理员
  1. 蜜獾哥

    优秀、神秘、完美!

  2. 白云朵朵

    学习中

个人中心
购物车
优惠劵
有新私信 私信列表
搜索