【问题标题】:Python ThreadPoolExecutor: future.result randomly returns NonePython ThreadPoolExecutor:future.result 随机返回 None
【发布时间】:2020-09-02 06:51:27
【问题描述】:

所以我有以下线程代码:

with concurrent.futures.ThreadPoolExecutor() as executor:
                    futures = []
                    for url in total_links:
                        futures.append(executor.submit(process_url, input_url=url))
                    for future in concurrent.futures.as_completed(futures):
                        print('RESULT INSIDE')
                        result = future.result() #Returns None randomly
                        print(result)
                        records.append(result)

有时future.result() 返回无。下面是process_url函数:

def process_url(input_url):
    res = None
    sleep(0.07)
    r = session.get(input_url, headers=headers, cookies=c, cert=cert, timeout=20)

    if r.status_code == 200:
        soup = BeautifulSoup(r.text, 'lxml')
        res = get_status(soup)
        print('Inside Process URL')
        print(res)
        print('======================')
    return res

res 将始终有可用的数据,但不会在线程下获取该数据。我还补充说它是随机发生的,也就是说,如果我运行脚本 5 次,那么至少会返回一次 None

【问题讨论】:

  • 您能否将process_url 方法封装在try...exception 块中,看看是否有任何异常被抛出并打印出来?在这种情况下,process_url 可能会返回 None
  • @vshenoy 抱歉回复晚了。不,没有抛出异常。无一例外,它都显示了任何东西
  • process_url 中添加一个else 子句并在其中打印,我敢打赌你会看到它被打印出来,这意味着一些URL 返回了非200 状态。无论是那个,还是你没有显示的 get_status,都可以返回 None。
  • @user4815162342 没有打印函数总是返回正确的值。
  • 您是否也在else 子句中添加了它?您是否在get_status 末尾添加了print(您仍然没有在问题中显示)?

标签: python python-multithreading threadpoolexecutor


【解决方案1】:

因此可能存在几个问题,但最值得注意的是,如果您没有收到 200 的状态代码,futures 对象将返回 None。例如,假设一个线程去检索一个 URL,但后面的线程无法到达主机,请求超时等,该线程将报告 None。

您可以通过以下方式验证此行为:

  1. 确保每个请求都在实际工作,例如确保 res=None 更改为线程中的成功状态。如果请求超时怎么办?您要返回这些详细信息吗?如果不是,则 res=None

  2. 添加逻辑以显示错误,例如确保 res=None 引用了响应。

    def process_url(input_url):
     res = None
     sleep(0.07)
     r = session.get(input_url, headers=headers, cookies=c, cert=cert, timeout=20)
    
     if r.status_code == 200:
         soup = BeautifulSoup(r.text, 'lxml')
         res = get_status(soup)
         print('Inside Process URL')
         print(res)
         print('======================')
     if r.status_code != 200:
         res = r.text
     return res
    

我可能会使用字典而不是数组作为期货对象,这样您就可以通过它的 url 引用每个线程。现在,它的索引。这样你就可以知道哪个url是罪魁祸首了。

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 20): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
            return "Something went wrong!"
        else:
            print('%r page is %d bytes' % (url, len(data)))
            return "Success!"

但是您正在运行的进程不是“随机”返回 None。 res 对象在您执行期间引用 None 。您可能还会收到 None 对象的唯一一次是线程没有收集结果。以下是供参考的文档。

https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Future.result

【讨论】:

    猜你喜欢
    • 2022-12-12
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 2019-04-26
    • 2013-04-07
    • 2014-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多