Python多线程邮件验证列表不同步问题求助
多线程邮件验证结果错位问题解决
你的推测完全正确——多线程环境下任务完成顺序不固定,先结束的线程会先把结果追加到列表,导致emails_list、deliverable_list、hostexists_list的索引无法一一对应,最终Excel里的结果和邮箱错位。
原代码的核心问题是将邮箱与验证结果分开存储,依赖线程执行顺序保证索引同步,这在多线程场景下根本不可靠。下面给出两种可行的修正方案:
方案一:使用ThreadPoolExecutor(推荐,代码更简洁可控)
concurrent.futures.ThreadPoolExecutor可以直接获取每个任务的返回值,我们可以让每个任务返回绑定了邮箱的结果字典,最后统一整理成DataFrame:
import pandas as pd import csv from email_verifier import Verifier from concurrent.futures import ThreadPoolExecutor, as_completed csvFilename = r'test2.csv' emails_list = [] # 读取邮箱列表 with open(csvFilename, 'r', encoding="utf-8") as csvFile: csvreader = csv.reader(csvFile) next(csvreader) # 跳过表头行 for row in csvreader: _, email = [str(val) for val in row] emails_list.append(email) def verify_email(email): try: verifier = Verifier(source_addr='example@gmail.com') result = verifier.verify(email) return { 'Email': email, 'Deliverable': result["deliverable"], 'Host exists': result["host_exists"] } except Exception as e: # 异常时返回默认值,避免结果缺失 print(f"验证邮箱 {email} 失败: {str(e)}") return { 'Email': email, 'Deliverable': False, 'Host exists': False } # 配置并发线程数 max_workers = 5 results = [] with ThreadPoolExecutor(max_workers=max_workers) as executor: # 提交所有验证任务 future_map = {executor.submit(verify_email, email): email for email in emails_list} # 遍历完成的任务,收集结果 for future in as_completed(future_map): results.append(future.result()) # 转换为DataFrame,可选:保持原邮箱顺序 df = pd.DataFrame(results) df = df.set_index('Email').reindex(emails_list).reset_index() # 保存到Excel df.to_excel('gmail_multi_thread_1.xlsx', index=False)
方案二:基于原生threading模块修改(兼容原代码结构)
如果不想更换线程管理方式,可以通过线程锁保证结果列表的原子操作,同时将邮箱与验证结果绑定成元组存储:
import threading import time import pandas as pd import csv from email_verifier import Verifier maxthreads = 5 pool_sema = threading.Semaphore(value=maxthreads) results_list = [] # 存储格式:(Email, Deliverable, Host exists) lock = threading.Lock() # 线程锁,防止多线程同时写入列表 csvFilename = r'test2.csv' emails_list = [] with open(csvFilename, 'r', encoding="utf-8") as csvFile: csvreader = csv.reader(csvFile) next(csvreader) # 跳过表头 for row in csvreader: _, email = [str(val) for val in row] emails_list.append(email) def task(email): pool_sema.acquire() try: verifier = Verifier(source_addr='example@gmail.com') result = verifier.verify(email) # 加锁后写入结果,保证线程安全 with lock: results_list.append(( email, result["deliverable"], result["host_exists"] )) time.sleep(3) except Exception as e: print(f"验证邮箱 {email} 失败: {str(e)}") with lock: results_list.append((email, False, False)) finally: pool_sema.release() def create_threads(): threads = [threading.Thread(target=task, args=(email,)) for email in emails_list] for t in threads: t.start() for t in threads: t.join() create_threads() # 转换为DataFrame,可选:保持原邮箱顺序 df = pd.DataFrame(results_list, columns=['Email', 'Deliverable', 'Host exists']) df = df.set_index('Email').reindex(emails_list).reset_index() df.to_excel('gmail_multi_thread_1.xlsx', index=False)
关键改进点
- 绑定邮箱与结果:不再分开存储三个独立列表,将每个邮箱和对应的验证结果作为一个整体存储,从根源上避免索引错位。
- 线程安全操作:方案二中通过
threading.Lock保证对结果列表的修改是原子操作,防止多线程同时写入导致的数据混乱。 - 可选顺序保持:通过
reindex方法可以让最终Excel表格保持原邮箱列表的顺序,不受线程完成顺序影响。
内容的提问来源于stack exchange,提问作者SAHU
相关产品推荐
相关产品推荐

