From aeea2181cc4348a0ecc388e2c5dbba34ff36cbbb Mon Sep 17 00:00:00 2001 From: milk <53408947@qq.com> Date: Fri, 7 Nov 2025 21:58:02 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E6=89=B9=E9=87=8F=E5=81=9C?= =?UTF-8?q?=E6=AD=A2=E4=BB=BB=E5=8A=A1=E4=B8=BA=E5=B9=B6=E8=A1=8C=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Module/FlaskService.py | 4 +- Utils/ThreadManager.py | 63 ++++++++++++------ .../__pycache__/ThreadManager.cpython-312.pyc | Bin 10572 -> 11794 bytes 3 files changed, 43 insertions(+), 24 deletions(-) diff --git a/Module/FlaskService.py b/Module/FlaskService.py index 1a49a4e..6ba5eb2 100644 --- a/Module/FlaskService.py +++ b/Module/FlaskService.py @@ -734,8 +734,8 @@ def delete_last_message(): @app.route("/stopAllTask", methods=['POST']) def stopAllTask(): idList = request.get_json() - code, msg = ThreadManager.batch_stop(idList) - return ResultData(code, [], msg).toJson() + code, msg, data = ThreadManager.batch_stop(idList) + return ResultData(code, data, msg).toJson() # 切换账号 @app.route('/changeAccount', methods=['POST']) diff --git a/Utils/ThreadManager.py b/Utils/ThreadManager.py index ddd6804..c39a897 100644 --- a/Utils/ThreadManager.py +++ b/Utils/ThreadManager.py @@ -4,6 +4,7 @@ import threading import ctypes import inspect import time +from concurrent.futures import ThreadPoolExecutor, as_completed from typing import Dict, Optional, List, Tuple, Any from Utils.LogManager import LogManager @@ -172,36 +173,54 @@ class ThreadManager: return 1001, "failed" @classmethod - def batch_stop(cls, udids: List[str], join_timeout_each: float = 2.0, - retries_each: int = 5, wait_step_each: float = 0.2) -> Tuple[int, str]: + def batch_stop(cls, udids: List[str]) -> Tuple[int, str, List[str]]: """ - 先全量执行一遍 -> 记录失败 -> 对失败重试 3 轮(每轮间隔 1 秒) - 全部完成后统一返回: - 全成功 : (200, "停止任务成功") - 仍有失败: (1001, "停止任务失败") + 并行批量停止(简化版): + - 只接收 udids 参数 + - 其他参数写死:join_timeout=2.0, retries=5, wait_step=0.2 + - 所有设备同时执行,失败的重试 3 轮,每轮间隔 1 秒 + - 返回: + (200, "停止任务成功", []) + (1001, "停止任务失败", [失败udid...]) """ - udids = udids or [] + if not udids: + return 200, "停止任务成功", [] + + join_timeout = 2.0 + retries = 5 + wait_step = 0.2 + retry_rounds = 3 + round_interval = 1.0 + + def _stop_one(u: str) -> Tuple[str, bool]: + ok = cls._stop_once(u, join_timeout, retries, wait_step) + return u, ok + + # === 第一轮:并行执行所有设备 === fail: List[str] = [] + with ThreadPoolExecutor(max_workers=len(udids)) as pool: + futures = [pool.submit(_stop_one, u) for u in udids] + for f in as_completed(futures): + u, ok = f.result() + if not ok: + fail.append(u) - # 第一轮 - for u in udids: - ok = cls._stop_once(u, join_timeout_each, retries_each, wait_step_each) - if not ok: - fail.append(u) - - # 三轮只对失败重试 - for _ in range(3): + # === 对失败的设备重试 3 轮(每轮间隔 1 秒) === + for _ in range(retry_rounds): if not fail: break - time.sleep(1.0) + time.sleep(round_interval) remain: List[str] = [] - for u in fail: - ok = cls._stop_once(u, join_timeout_each, retries_each, wait_step_each) - if not ok: - remain.append(u) + with ThreadPoolExecutor(max_workers=len(fail)) as pool: + futures = [pool.submit(_stop_one, u) for u in fail] + for f in as_completed(futures): + u, ok = f.result() + if not ok: + remain.append(u) fail = remain + # === 返回结果 === if not fail: - return 200, "停止任务成功" + return 200, "停止任务成功", [] else: - return 1001, "停止任务失败" \ No newline at end of file + return 1001, "停止任务失败", fail \ No newline at end of file diff --git a/Utils/__pycache__/ThreadManager.cpython-312.pyc b/Utils/__pycache__/ThreadManager.cpython-312.pyc index b13febb48bb4183ddd73fa816e05ef5d61480e43..2872c7d7ae87ccdf6697333ac88d8898caab8ce4 100644 GIT binary patch delta 3365 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