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

使用concurrent.futures时如何保持返回列表与原始输入顺序一致

解决方案

问题原因

你当前结果顺序随机的核心原因是concurrent.futures.as_completed()会按任务完成的先后顺序返回future对象,和任务提交的顺序无关,所以直接按返回顺序追加结果,自然和原始URL列表的顺序不匹配。

方案1:使用executor.map()(最简洁的标准实现)

executor.map()是官方提供的专门针对批量顺序返回的接口,返回结果的顺序和传入的可迭代对象(这里就是你的URL列表)顺序完全一致,代码改动量最小。
修改后的完整代码如下:

from urllib.request import urlopen
from bs4 import BeautifulSoup
import concurrent.futures

# 可根据自身需求调整线程数
CONNECTIONS = 8
archive_url_list = ['https://web.archive.org/web/20171220002410/http://www.manueldrivingschool.co.uk:80/areas-covered-for-driving-lessons', 'https://web.archive.org/web/20210301102140/https://www.manueldrivingschool.co.uk/contact.php', 'https://web.archive.org/web/20210301102140/https://www.manueldrivingschool.co.uk/contact.php', 'https://web.archive.org/web/20171220002415/http://www.manueldrivingschool.co.uk:80/contact', 'https://web.archive.org/web/20160520140505/http://www.manueldrivingschool.co.uk:80/about.php', 'https://web.archive.org/web/20180102123922/http://www.manueldrivingschool.co.uk:80/about']

def get_archive_h1(h1_url):
    try:
        html = urlopen(h1_url)
        bsh = BeautifulSoup(html.read(), 'lxml')
        return bsh.h1.text.strip()
    except Exception:
        return "No Data Received!"

def concurrent_calls():
    with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
        # map返回的结果顺序和archive_url_list完全对应
        return list(executor.map(get_archive_h1, archive_url_list))

if __name__ == '__main__':
    archive_h1_list = concurrent_calls()
    print(archive_h1_list)

方案2:绑定索引提交任务(适合需要自定义任务控制的场景)

如果你需要使用submit+as_completed的组合做更灵活的任务控制(比如实时打印完成进度),可以在提交任务时绑定每个future对应的原始索引,任务完成后把结果写入结果列表的对应位置即可保证顺序。
仅需要修改concurrent_calls函数部分:

def concurrent_calls():
    # 先初始化和URL列表等长的结果列表
    archive_h1_list = [None] * len(archive_url_list)
    with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
        # 提交任务时建立future和原始索引的映射关系
        future_map = {executor.submit(get_archive_h1, url): idx for idx, url in enumerate(archive_url_list)}
        for future in concurrent.futures.as_completed(future_map):
            # 获取当前future对应的原始索引
            current_idx = future_map[future]
            try:
                data = future.result()
            except Exception:
                data = "No Data Received!"
            # 把结果写入对应索引位置
            archive_h1_list[current_idx] = data
    return archive_h1_list

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 06:09:04