PyQt5程序随机触发exit code -1073740791错误排查求助
问题背景
基于PyQt5 + Python3.9开发的批量数据下载程序,通过QEventLoop.exec_()向服务器发起请求,接收完所有数据后调用QEventLoop.exit()结束循环。程序处理约1000个任务时,会随机触发错误码-1073740791(0xC0000409)崩溃,崩溃点无固定规律,可能出现在任务前、中、后期,甚至不出现。经初步排查,怀疑频繁开关文件是诱因。
请求数据代码片段:
def day_kiwoom_db(self, code=None, date=None, sPrevNext="0"): QTest.qWait(3600) self.temp_screen1 += 1 if self.temp_screen1 >= 150: self.temp_screen1 = 0 self.temp_screen3 += 1 self.dynamicCall("SetInputValue(QString, QString)", "종목코드", code) self.dynamicCall("SetInputValue(QString, QString)", "수정주가구분", "1") if date != None: self.dynamicCall("SetInputValue(QString, QString)", "기준일자", date) self.dynamicCall("CommRqData(QString, QString, int, QString)", "주식일봉차트조회", "opt10081", sPrevNext, "%s" % (int(self.screen_calculation_stock) + self.temp_screen3)) self.calculator_event_loop.exec_()
接收数据代码片段(存在缩进错误):
def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext): if sRQName == "주식일봉차트조회": code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드") code = code.strip() cnt = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName) for i in range(cnt): close_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가") close_price = close_price.strip().lstrip('+').lstrip('-') value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래량") value = value.strip() trading_value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래대금") # 출력 : 000070 trading_value = trading_value.strip() date = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "일자") date = date.strip() start_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "시가") # 출력 : 000070 start_price = start_price.strip().lstrip('+').lstrip('-') high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "고가") # 출력 : 000070 high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "고가") high_price = high_price.strip().lstrip('+').lstrip('-') low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "저가") # 출력 : 000070 low_price = low_price.strip().lstrip('+').lstrip('-') print("%s,%s,%s,%s,%s,%s\n" % (date, start_price, close_price, high_price, low_price, value)) f = open(self.datafile_path, "a", encoding="utf8") f.write("%s,%s,%s,%s,%s,%s\n" % (date, start_price, close_price, high_price, low_price, value)) f.close() if sPrevNext == "2" and self.chart_req_time > 0: self.day_kiwoom_db(code=code, sPrevNext=sPrevNext) self.chart_req_time -= 1 else: print("총 일수 %s" % len(self.calcul_data)) self.chart_req_time = self.chart_req_tmp self.calculator_event_loop.exit()
解决思路与修复方案
1. 修复代码缩进错误
原接收数据代码中,value = value.strip()和trading_value = trading_value.strip()的缩进跳出了for循环,会导致变量值异常,触发不可预期的错误。必须将这两行代码缩进至for循环内部。
2. 优化文件IO操作
频繁的open()/close()会增加系统资源开销,容易引发资源竞争或句柄泄漏。优化方案:
- 内存缓存批量数据,一次性写入文件
- 单个任务周期内保持文件打开状态
修改后的接收数据代码(批量写入版):
def trdata_slot(self, sScrNo, sRQName, sTrCode, sRecordName, sPrevNext): if sRQName == "주식일봉차트조회": code = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, 0, "종목코드") code = code.strip() cnt = self.dynamicCall("GetRepeatCnt(QString, QString)", sTrCode, sRQName) # 内存缓存数据,减少IO次数 data_lines = [] for i in range(cnt): close_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "현재가") close_price = close_price.strip().lstrip('+').lstrip('-') value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래량") value = value.strip() # 修复缩进 trading_value = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "거래대금") trading_value = trading_value.strip() # 修复缩进 date = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "일자") date = date.strip() start_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "시가") start_price = start_price.strip().lstrip('+').lstrip('-') high_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "고가") high_price = high_price.strip().lstrip('+').lstrip('-') low_price = self.dynamicCall("GetCommData(QString, QString, int, QString)", sTrCode, sRQName, i, "저가") low_price = low_price.strip().lstrip('+').lstrip('-') line = "%s,%s,%s,%s,%s,%s\n" % (date, start_price, close_price, high_price, low_price, value) print(line.strip()) data_lines.append(line) # 批量写入文件,添加异常捕获 if data_lines: try: with open(self.datafile_path, "a", encoding="utf8") as f: f.writelines(data_lines) except IOError as e: print(f"文件写入失败: {e}") # 可选:将失败数据缓存,后续重试 if sPrevNext == "2" and self.chart_req_time > 0: self.day_kiwoom_db(code=code, sPrevNext=sPrevNext) self.chart_req_time -= 1 else: print("총 일수 %s" % len(self.calcul_data)) self.chart_req_time = self.chart_req_tmp self.calculator_event_loop.exit()
3. 错误码0xC0000409的额外排查点
该错误对应Windows的STATUS_STACK_BUFFER_OVERRUN,除文件IO外,还需排查:
- 字符串处理时的缓冲区溢出(如
strip()或字符串拼接异常) dynamicCall调用时参数类型不匹配,导致内存访问错误- Kiwoom接口的线程安全问题,避免并发请求过载
4. 事件循环与并发优化
- PyQt槽函数运行在主线程,大量IO操作可能阻塞事件循环,可将文件写入移至
QThreadPool单独处理 - 调整
QTest.qWait(3600)的等待时间为更合理值,或用信号量控制并发请求数量,避免接口过载
内容的提问来源于stack exchange,提问作者gety
相关产品推荐
相关产品推荐

