多线程与单线程的区别:
- 单线程顺序执行:ABCDEFG,HIJKLMN
- 单线程异步执行:ABC,KLMN,EFGHI,错开执行避免I/O之类的长时间等待卡住线程【WinWait】
- 多线程:一个进程内可有多个线程ABCDEFG同时执行互不干扰
- 多进程:创建多个进程ABCDEFG并互相通信,来达到仿多线程的效果。
不控制主进程的话,使用方法如下:
新建进程示例,可以是代码,也可以是路径:
进程1 := ComProcess("C:\Program Files\AutoHotkey\Lib\FindText.ahk")
在目标进程中调用一个名为 "Function" 的函数:
进程1.Function(params)
获取进程1的一个全局变量:
value := 进程1["VarName"] value := 进程1.VarName
对进程1的一个全局变量赋值:
进程1["VarName"] := value 进程1.VarName := value
对进程1创建一个Class的实例:
value := 进程1["__ComProcess"].__New("ClassName", params)
另一个精简但不能共享对象的多进程:多进程代替多线程函数 – 精简版
尝试双向通信的多进程库,ComProcess函数用来控制和调用新进程很方便。但是新进程向主进程发送控制,我写了一个Class 变量赋值回调来实现。
完整的双向通信示例:
#Requires AutoHotkey v1.1.33+ #SingleInstance Force SetBatchLines -1 Gosub 加载新进程标签 进程1.进程共享变量 := New 变量赋值回调("新进程触发回调函数") Gui -MinimizeBox -MaximizeBox +AlwaysOnTop Gui Add, Edit, w300 R2 v通信显示 g同步发送 Gui Show, x850 w330 y400, P主进程 - 互相通信同步演示,请输入文字 Loop { Sleep 80 MouseGetPos, x, y ToolTip % "P-主进程持续运算演示-" A_Index, x+10, y-70 } Return 同步发送: GuiControlGet, 获取编辑框内容,, 通信显示 进程1.Gui同步更新(获取编辑框内容, "通信显示") Return GuiClose: ExitApp Return ; F3键做新进程的开、关、一键开关的演示【只有主进程端能够新建进程】 F3:: ; 进程1 := ComProcess(新代码1) 进程1 := "" ; 进程1:=(Toggle:=!Toggle) ? ComProcess(新代码1) : "" Return 新进程触发回调函数(newValue) { GuiControl,, 通信显示, %newValue% } class 变量赋值回调 { __New(changeCallback) { this._onChangeCallback := Func(changeCallback) } 回调变量[] { get { return this._value } set { this._value := value , (this._onChangeCallback && this._onChangeCallback.Call(this._value)) return this._value } } } 加载新进程标签: 新代码1= ( ` % Gui -MinimizeBox -MaximizeBox +AlwaysOnTop Gui Add, Edit, w300 R2 v通信显示 g同步发送 Gui Show, x850 w330 y500, F3新进程 - 互相通信同步演示,请输入文字 Loop { Sleep 80 MouseGetPos, x, y ToolTip % "F3-新进程持续运算演示-" A_Index, x+10, y-30 } Return 同步发送: GuiControlGet, 获取编辑框内容,, 通信显示 进程共享变量.回调变量 := 获取编辑框内容 Return Gui同步更新(Value, ControlID) { GuiControl,, %ControlID%, %Value% } GuiClose: ExitApp Return ) 进程1 := ComProcess(新代码1) Return /* 在目标进程中调用一个名为 "Function" 的函数。 进程1.Function(params) 获取进程1的一个全局变量 value := 进程1["VarName"] value := 进程1.VarName 对进程1的一个全局变量赋值 进程1["VarName"] := value 进程1.VarName := value 创建一个Class的实例 value := 进程1["__ComProcess"].__New("ClassName", params) 已知限制: 如果脚本在运行远程脚本调用的方法时退出,则远程脚本将收到错误。 AutoHotkey 如何在本地与 COM 对象交互以及 AutoHotkey 对象如何通过 COM 接口响应请求也存在一些限制。 变量无法通过 ByRef 传递到远程对象。 有些调用是不明确的;例如,foo.bar 触发器 foo.__Call 进而foo.__Get。 */ ; By dbgba Thank thqby ComProcess(PathsOrCode, v1Interpreter="", Timeout=30, NoTrayIcon="#NoTrayIcon") { Static IDispatch, ComProcessNum := 0 , _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64")) , PIDLabel := DllCall("GetCurrentProcessId") if (v1Interpreter="") { if A_Is64bitOS SetRegView 64 RegRead, InstallDir, HKLM\SOFTWARE\AutoHotkey, InstallDir v1Interpreter := InstallDir="" ? A_AhkPath : InstallDir "\AutoHotkey.exe" } if !FileExist(v1Interpreter) throw Exception("请将参数2的AHK解释器路径设置正确!") lresult := DllCall("oleacc\LresultFromObject", "Ptr", &IDispatch, "Ptr", 0, "Ptr", &(client := { proxy: 0 }), "Ptr") if IsObject(PathsOrCode) { t := PathsOrCode, PathsOrCode := "" For __, p in t PathsOrCode .= "`n#include " p } v1script := Format(" ( #Persistent " NoTrayIcon " class __ComProcess { __New(name, args*) { static _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, ""int64""), ""int64""), DllCall(""oleacc\ObjectFromLresult"", ""ptr"", {}, ""ptr"", &IDispatch, ""ptr"", 0, ""ptr*"", idisp := 0), ComObject(9, idisp).proxy := new __ComProcess(), ObjRelease(idisp)), hMapping := DllCall(""kernel32\CreateFileMapping"", ""Ptr"", -1, ""Ptr"", 0, ""UInt"", 0x4, ""UInt"", 0, ""UInt"", 4, ""Str"", ""AHKLoadStatus" PIDLabel . ++ComProcessNum """), pView := DllCall(""kernel32\MapViewOfFile"", ""Ptr"", hMapping, ""UInt"", 0x2, ""UInt"", 0, ""UInt"", 0, ""UInt"", 4) return IsObject(name) ? new name(args*) : new %name%(args*) } __Call(name, args*) { Global if (IsObject(args) && %name%!="""") return __ComProcessVar__ := %name% return %name%(args*) } ; __Get(name) COM机制无法触发,故删掉 __Set(name, val) { Global return %name% := val } __Delete() { SetTimer __ComProcessExitApp__, -1 return __ComProcessExitApp__: ExitApp } } {} )", lresult, FileExist(PathsOrCode) ? "" : PathsOrCode) if (v1Interpreter ~= "i)\.dll$") { if (!DllCall("GetModuleHandle", "str", v1Interpreter) && !DllCall("LoadLibrary", "str", v1Interpreter)) { DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp) throw Exception("load AutoHotkey.dll fail") } if !(threadID := DllCall(v1Interpreter "\NewThread", "str", v1script "`n" (FileExist(PathsOrCode) ? "#Include " PathsOrCode : ""), "str", "", "str", "", "cdecl uint")) { DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp) throw Exception("Failed to load script") } _exec := {ProcessID : DllCall("GetCurrentProcessId")} } else { if FileExist(PathsOrCode) _exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /include """ PathsOrCode """ *") else _exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /CP0 *") _exec.StdIn.Write(v1script), _exec.StdIn.Close() } Loop % Timeout*1000//15 { Sleep 15 hMap := DllCall("kernel32\OpenFileMapping", "UInt", 0x2, "Int", 0, "Str", "AHKLoadStatus" PIDLabel . ComProcessNum) , pView := DllCall("kernel32\MapViewOfFile", "Ptr", hMap, "UInt", 0x2, "UInt", 0, "UInt", 0, "UInt", 4) } Until ((isLoaded := NumGet(pView+0, 0, "Int"))=0) if (isLoaded!=0) Throw Exception("AHK新进程启动超时或故障!") Sleep 10 return client.proxy }
声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。
评论(0)