为何Python多线程未缩短脚本运行时长?求技术支持
问题分析与解决方案
核心问题:线程池未实际并行执行
你当前的代码只向ThreadPoolExecutor提交了一个threadrun任务,这个任务内部是单线程循环遍历所有用户,线程池里的其他999个线程完全闲置,所以无论设置多少线程数,运行时长都不会有变化。
其他潜在问题
- 遍历列表时修改元素的bug:在遍历
n_keywords的同时调用remove(k2),会导致列表迭代器跳过后续元素,部分关键词无法被正确处理。 - 文件写入线程不安全:多个线程同时写入同一个文件句柄,会导致输出内容错乱、丢失。
- 线程数设置不合理: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
相关产品推荐
相关产品推荐

