|
|
做批量任务时,单线程脚本永远在排队:一个窗口点完才轮到下一个,10 个号跑一轮要十几分钟。真正的提效是把任务拆成队列,让多个工作线程同时消费。本文用 AIWROK 的 `thread` 引擎讲清楚一套能长期稳定跑的线程池写法。
为什么单线程不够
模拟点击是阻塞操作:一次 `clickPercent` 加上等待动画,至少要 200~500ms。如果一个脚本串行处理 5 个窗口,总耗时是线性叠加的。把每个窗口当成一个独立任务丢进队列,再用 N 个线程并发消费,总耗时近似除以 N。
核心结构:队列 + 互斥锁
多个线程共享同一个任务队列,取任务那一瞬间必须加锁,否则会出现两个线程抢到同一个任务。AIWROK 里用一个简单的 `Mutex` 守卫即可:
- var queue = [];
- var mutex = { locked: false };
- function take() {
- while (mutex.locked) sleep.millisecond(2);
- mutex.locked = true;
- var job = queue.length > 0 ? queue.shift() : null;
- mutex.locked = false;
- return job;
- }
复制代码
临界区越小越好——只在 `shift` 那一刻加锁,别把整个任务处理包进去。
工作线程怎么写
每个工作线程跑一个循环:取任务、执行、没有任务就短暂休眠后继续。关键点有三个:
- var running = true;
- function workerLoop() {
- while (running) {
- var job = take();
- if (job === null) { sleep.millisecond(120); continue; }
- try { doWork(job); }
- catch (e) { printl("任务异常: " + e); }
- }
- }
- for (var i = 0; i < 5; i++) {
- var t = new thread();
- t.runJsCode(workerLoop, "worker-" + i);
- }
复制代码
第一,`doWork` 一定要 `try/catch`,单个任务崩了不能把整个线程带死。第二,取不到任务时空转要短(120ms),别死循环占满 CPU。
主线程死掉子线程也死
AIWROK 的铁律:主线程一跑完,所有子线程和定时器全被回收。所以主线程不能跑完就结束,要用 `runTime.setTimeout` 递归保活:
- function keepAlive() {
- if (running) runTime.setTimeout(keepAlive, 1000);
- }
- keepAlive();
复制代码
线程间别抢同一个设备
多窗口并发的前提是它们操作的是不同目标。如果 5 个线程都去点同一个坐标,反而互相打架。正确做法是任务里带上各自的目标标识(窗口句柄、包名、坐标区),线程只处理自己那份。
收尾要干净
任务跑完别让线程空转:队列清空超过 5 秒就让 `workerLoop` 主动 `break` 退休,等所有线程都退出再把 `running` 复位。否则池子永远显示"运行中",再点启动会被判"已在运行"而空跑。
相关阅读
- 短信验证码中心AIWROK万能调用端
- clickPercent天然适配不同分辨率找控件点击
- floatUI深色控制台风格悬浮窗日志
|
|