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

如何用Python Requests加速循环并避免线程执行时重复输出?

问题根源

你遇到的重复输出(或输出混乱),主要是两个原因:

  • 多线程同时调用print时,标准输出流的操作不是线程安全的,多个线程的输出会互相干扰,看起来像重复;
  • 如果每个线程都完整遍历整个URL列表,会导致同一URL被多个线程重复处理,直接产生重复输出。
解决方案

1. 给输出加锁,避免线程抢占输出流

用threading.Lock()确保同一时间只有一个线程能执行print操作,解决输出混乱问题。

2. 拆分任务,每个线程处理独立的URL片段

把URL列表分成多份,每个线程只处理自己的那一部分,从根源避免重复处理同一个URL。

完整改进代码

import requests
import json
import threading

# 加载URL数据,用上下文管理器自动关文件
with open("urls.json") as f:
    data = json.load(f)
urls_list = data['urls']

# 创建线程锁,控制输出的线程安全
print_lock = threading.Lock()

def process_url_chunk(url_chunk):
    for url in url_chunk:
        try:
            r = requests.get(f"https://{url}")
            # 加锁后再输出,保证同一时间只有一个线程在打印
            with print_lock:
                print(f"=== 处理URL: {url} ===")
                print(r.headers)
                print("\n")
        except Exception as e:
            with print_lock:
                print(f"URL {url} 请求失败: {str(e)}")

def main():
    # 设置线程数,根据你的需求调整,别开太多,不然请求会被目标网站限制
    thread_num = 4
    # 拆分URL列表
    chunk_size = len(urls_list) // thread_num
    threads = []
    
    for i in range(thread_num):
        start = i * chunk_size
        # 最后一个线程处理剩下的所有URL,避免遗漏
        end = start + chunk_size if i != thread_num -1 else len(urls_list)
        current_chunk = urls_list[start:end]
        # 创建线程并启动
        t = threading.Thread(target=process_url_chunk, args=(current_chunk,))
        threads.append(t)
        t.start()
    
    # 等待所有线程跑完
    for t in threads:
        t.join()

if __name__ == "__main__":
    main()

关键改进点

  • 用with open()替代直接open(),自动关闭文件,避免资源浪费;
  • 加了print_lock,所有输出操作都在锁的保护下执行,彻底解决输出混乱/重复的问题;
  • 拆分URL列表,每个线程只处理自己的片段,不会重复处理同一URL;
  • 加了异常捕获,单个URL请求失败不会影响整个线程,错误信息也能安全输出。
更简洁的线程池写法

如果不想手动管理线程,可以用concurrent.futures.ThreadPoolExecutor,它会自动帮你拆分任务、管理线程:

import requests
import json
import threading
from concurrent.futures import ThreadPoolExecutor

with open("urls.json") as f:
    data = json.load(f)
urls_list = data['urls']

print_lock = threading.Lock()

def process_single_url(url):
    try:
        r = requests.get(f"https://{url}")
        with print_lock:
            print(f"=== 处理URL: {url} ===")
            print(r.headers)
            print("\n")
    except Exception as e:
        with print_lock:
            print(f"URL {url} 请求失败: {str(e)}")

def main():
    # 线程池最大线程数,按需调整
    with ThreadPoolExecutor(max_workers=4) as executor:
        executor.map(process_single_url, urls_list)

if __name__ == "__main__":
    main()

这个版本代码更简洁,不用手动拆分列表,ThreadPoolExecutor会自动把任务分配给各个线程,效率一样高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:25:17