多进程股票策略代码在新Win10电脑上无法终止求助
多进程股票策略代码在Windows环境下进程挂起的排查与解决思路
问题背景
我开发的多进程股票策略代码在两台Windows 10(Python 3.10)机器上运行正常,但在新电脑执行生成PNG图片的逻辑时出现异常——进程永远无法终止,疑似某个子进程未正常结束。已确认三台机器的Python包版本完全一致,运行日志前期内容完全相同,正常机器进程退出码为0,耗时约19秒。核心多进程执行代码如下:
def run_strategy_parallel(self): """Run the strategy for multiple tickers using multiple threads.""" self.input_data_handler.download_stock_data_parallel() tickers = self.input_data_handler.get_tickers_list() start_time = datetime.now() print(f"{40*'='}\nStarting time: {start_time}\n{40*'-'}") with ProcessPoolExecutor() as executor: results = executor.map(self._process_strategy_wrapper, tickers) self._write_output(df=pd.concat(results)) timer_end = datetime.now() print(f"{40*'-'}\nFinishing time: {timer_end}") print(f"Time taken: {timer_end - start_time}") def _process_strategy_wrapper(self, ticker) -> pd.DataFrame: """Wrapper to catch and print exceptions from the strategy.""" try: return self._process_strategy(ticker=ticker) except Exception as e: print(80*"=") print(f"Error processing strategy for ticker: {ticker}") print(80*"-") traceback.print_exception(e) def _process_strategy(self, ticker: str) -> pd.DataFrame: df_stock = self.input_data_handler.get_stock_data(ticker=ticker) if df_stock is None: print(f"No stock data available for {ticker}. Skipping...") return pd.DataFrame() df_buy = self.buy_signal_finder.run( ticker=ticker, stock_data=df_stock, ) df_sell = self.sell_signal_finder.run( ticker=ticker, stock_data=df_stock, ) return pd.concat([df_buy, df_sell])
排查思路
- 定位卡住的子进程
在_process_strategy中添加详细日志,记录每个ticker的PNG生成开始、结束时间,确认是所有进程挂起还是特定ticker的进程卡住。 - 验证多进程资源配置
新电脑CPU核心数可能与旧机器差异大,ProcessPoolExecutor默认使用全部核心,可能引发资源竞争。手动指定max_workers(比如设为4或8),观察是否还会挂起。 - 检查PNG生成的系统依赖
即使Python包版本一致,Windows底层依赖(如libpng、绘图库的系统动态库)可能缺失。单独运行PNG生成的代码片段,验证是否能正常执行。 - 排查进程间通信阻塞
executor.map会等待所有子进程返回结果,若返回的DataFrame包含不可序列化对象或数据量过大,可能导致通信阻塞。临时修改代码,让子进程只执行PNG生成不返回数据,测试是否还会挂起。 - 查看系统事件日志
打开Windows事件查看器,检查应用程序日志中是否有Python进程的崩溃、权限报错或资源耗尽记录。 - 测试单进程模式
临时替换多进程为单进程循环执行,若单进程正常,说明问题出在多进程调度或进程交互环节。
解决建议
- 给任务添加超时机制
改用executor.submit配合as_completed,给每个任务设置超时,避免单个进程卡住导致整体挂起:from concurrent.futures import as_completed with ProcessPoolExecutor(max_workers=4) as executor: futures = {executor.submit(self._process_strategy_wrapper, ticker): ticker for ticker in tickers} results = [] for future in as_completed(futures, timeout=30): ticker = futures[future] try: res = future.result() results.append(res) except Exception as e: print(f"Task for {ticker} timed out or failed: {e}") - 配置绘图库的多进程兼容模式
若用matplotlib生成PNG,在子进程的绘图代码开头添加后端配置,避免GUI相关阻塞:import matplotlib matplotlib.use('Agg') # 使用非交互式后端 - 确保文件写入权限
明确指定PNG输出目录为用户有权限的路径(如os.path.expanduser("~/output")),并添加文件写入的异常捕获。 - 避免子进程共享全局对象
Windows多进程通过pickle复制对象,若input_data_handler等实例包含不可序列化资源(如文件句柄),会导致异常。改为在子进程中重新初始化这些对象,而非依赖父进程实例。
内容的提问来源于stack exchange,提问作者Artrade
相关产品推荐
相关产品推荐

