You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter多线程更新Treeview时程序无响应问题求助

URL关键词检测工具GUI无响应问题的技术解决方案

问题概述

开发基于URL列表检测网站关键词的Tkinter程序,采用队列在主线程更新Treeview,但程序仍不时出现无响应情况,代码分为logic.py和ui.py。

核心问题分析与修复建议

1. 将检测逻辑完全移至子线程,避免阻塞主线程

当前start_checking方法直接在主线程调用logic.start_check,其中read_csv和线程池初始化操作会占用主线程资源,导致GUI卡顿。需将整个检测流程放入独立子线程。

修改ui.py的start_checking方法:

def start_checking(self):
    if not self.csv_file_path:
        messagebox.showerror("错误", "请先选择CSV文件。")
        return

    if not self.keywords:
        messagebox.showerror("错误", "请先设置关键词。")
        return

    if not self.urls:
        messagebox.showerror("错误", "CSV文件中无URL。")
        return

    # 清空Treeview
    for item in self.result_treeview.get_children():
        self.result_treeview.delete(item)
    
    # 禁用开始按钮,防止重复触发
    self.start_button.config(state=tk.DISABLED)

    # 将检测逻辑放入子线程
    def run_check():
        logic = Logic(self)
        logic.start_check(self.csv_file_path, self.keywords)
        # 检测完成后恢复按钮状态
        self.master.after(0, lambda: self.start_button.config(state=tk.NORMAL))
    
    self.checking_thread = threading.Thread(target=run_check)
    self.checking_thread.daemon = True
    self.checking_thread.start()

2. 优化Treeview更新逻辑,提升渲染效率

当前将结果拼接成字符串插入Treeview,既不符合列对应逻辑,也会导致频繁的GUI渲染操作。需按列插入数据,并批量处理队列中的结果,减少GUI更新次数。

修改ui.py的handee方法:

def handee(self, root):
    # 批量处理队列中所有待更新数据,减少GUI渲染次数
    while not self.msg_queue.empty():
        data = self.msg_queue.get()
        # 按列顺序整理数据:URL + 各关键词状态 + 错误信息
        values = [data['url']]
        for keyword in self.keywords:
            values.append(data.get(keyword, '不存在'))
        values.append(data.get('error', ''))
        # 插入Treeview
        self.result_treeview.insert('', 'end', values=values)
    # 调整间隔为100ms,平衡响应速度与资源占用
    root.after(100, self.handee, root)

同时修正update_result_treeview_header方法,添加错误列:

def update_result_treeview_header(self):
    self.result_treeview['columns'] = ["URL"] + self.keywords + ["错误信息"]
    self.result_treeview.heading("#0", text="序号")
    self.result_treeview.column("#0", width=50)
    self.result_treeview.heading("URL", text="URL")
    for keyword in self.keywords:
        self.result_treeview.heading(keyword, text=keyword)
    self.result_treeview.heading("错误信息", text="错误信息")

3. 优化网络请求与线程资源管理

  • 使用requests.Session复用HTTP连接,减少网络开销;
  • 降低线程池最大工作线程数,避免过多并发请求导致的系统资源耗尽。

修改logic.py的get_url_response方法,添加Session复用:

def __init__(self, app):
    self.app = app
    # 初始化Session,复用连接
    self.session = requests.Session()
    self.session.proxies = {
        'http': 'http://127.0.0.1:10809',
        'https': 'http://127.0.0.1:10809'
    }

@retry(stop_max_attempt_number=3, wait_fixed=1000)
def get_url_response(self, url):
    response = self.session.get(url, timeout=5)
    if response.status_code != 200:
        raise requests.exceptions.RequestException(f'HTTP状态码错误: {response.status_code}')
    return response

调整process_all_urls的线程池大小:

def process_all_urls(self, urls, keywords):
    # 根据系统资源调整,建议设为5-8
    with ThreadPoolExecutor(max_workers=6) as executor:
        for url in urls:
            executor.submit(self.process_url, urls, url, keywords)

4. 修复CSV写入的线程安全问题

多个线程同时写入result.csv会导致文件内容错乱,需添加线程锁控制写入操作。

修改logic.py,添加文件锁:

import threading

class Logic:
    def __init__(self, app):
        self.app = app
        self.session = requests.Session()
        self.session.proxies = {
            'http': 'http://127.0.0.1:10809',
            'https': 'http://127.0.0.1:10809'
        }
        # 添加文件写入锁
        self.csv_lock = threading.Lock()

# 修改write_csv_row方法,添加锁
def write_csv_row(self, url, result_dict, error=None):
    with self.csv_lock:
        with open('result.csv', 'a', newline='', encoding='utf-8') as csvfile:
            fieldnames = ['url'] + list(result_dict.keys()) + ['error']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            if csvfile.tell() == 0:
                writer.writeheader()
            row_data = {'url': url}
            for key, value in result_dict.items():
                row_data[key] = '存在' if value else '不存在'
            row_data['error'] = error if error else ''
            writer.writerow(row_data)
            self.app.msg_queue.put(row_data)

额外优化建议

  • 添加进度显示:通过队列传递当前处理进度,在GUI中显示已处理/总URL数;
  • 异常捕获细化:区分网络超时、代理错误、HTTP错误等不同异常类型,提供更精准的错误信息;
  • 配置文件加载:启动时自动读取config.ini中的关键词和CSV路径,减少用户手动操作。

内容的提问来源于stack exchange,提问作者Tate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 12:19:54