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

为何Python多线程未缩短脚本运行时长?求技术支持

问题分析与解决方案

核心问题:线程池未实际并行执行

你当前的代码只向ThreadPoolExecutor提交了一个threadrun任务,这个任务内部是单线程循环遍历所有用户,线程池里的其他999个线程完全闲置,所以无论设置多少线程数,运行时长都不会有变化。

其他潜在问题

  1. 遍历列表时修改元素的bug:在遍历n_keywords的同时调用remove(k2),会导致列表迭代器跳过后续元素,部分关键词无法被正确处理。
  2. 文件写入线程不安全:多个线程同时写入同一个文件句柄,会导致输出内容错乱、丢失。
  3. 线程数设置不合理:1000个线程远超过实际需求,会带来大量上下文切换开销,反而降低效率。CPU密集型任务建议设置为CPU核心数,IO密集型任务可设为核心数的2-4倍。

修复后的代码

import re
import concurrent.futures
import time
from threading import Lock

setting1 = 101
setting2 = 321
setting3 = None

# 合理设置线程数,比如CPU核心数*2
threads = 8

start = time.perf_counter()

def load_keywords(keyword_file):
    with open(keyword_file, 'r') as keywordhandle:
        keywords = [keyword.strip() for keyword in keywordhandle.readlines()]
    return keywords

def gencombo(user, keywords):
    og_user = re.sub(r'\d', '', user)
    user_lower = og_user.lower()
    combos = []
    
    # 筛选匹配的关键词,避免在遍历中修改原列表
    n_keywords = [kw for kw in keywords if kw.lower() in user_lower]
    
    # 去重包含关系的关键词,创建新列表而非修改原列表
    filtered_keywords = []
    for k1 in n_keywords:
        # 保留不被其他关键词包含的项
        if not any(k2 != k1 and k2 in k1 for k2 in n_keywords):
            filtered_keywords.append(k1)
    
    for keyword in filtered_keywords:
        print(f"Combos added for: {user}")
        if setting1 is not None:
            combos.append(f"{user}:{keyword}{str(setting1)}")
        if setting2 is not None:
            combos.append(f"{user}:{keyword}{str(setting2)}")
        if setting3 is not None:
            combos.append(f"{user}:{keyword}{str(setting3)}")

    return '\n'.join(combos) if combos else None

def gencombos(input_file, output_file, keyword_file):
    keywords = load_keywords(keyword_file)
    # 读取所有用户到内存,避免多线程读取文件的问题
    with open(input_file, 'r') as combohandle:
        users = [user.strip() for user in combohandle if user.strip()]
    
    # 初始化文件锁,保证线程安全写入
    file_lock = Lock()
    
    def write_to_output(combo):
        if not combo:
            return
        with file_lock:
            with open(output_file, 'a') as handlenone:
                handlenone.write(f"{combo}\n")
    
    # 提交每个用户的处理任务到线程池
    with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor:
        # 使用map批量提交任务,自动处理结果
        results = executor.map(lambda user: gencombo(user, keywords), users)
        for result in results:
            write_to_output(result)

gencombos("users.txt", "output.txt", "keywords.txt")

finish = time.perf_counter()
input(f"Finished in {round(finish - start, 2)} seconds.")

关键修改说明

  • 任务拆分:将每个用户的gencombo处理作为独立任务提交给线程池,让多个线程并行处理不同用户。
  • 修复列表遍历bug:通过列表推导式和新列表存储筛选结果,避免遍历原列表时修改元素导致的迭代异常。
  • 线程安全写入:使用threading.Lock保证同一时间只有一个线程写入文件,避免内容错乱。
  • 合理设置线程数:将线程数调整为更合理的数值(如8),减少上下文切换开销。
  • 预读取用户列表:提前读取所有用户到内存,避免多线程同时读取文件可能出现的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:57:05