首页 > 解决方案 > 为什么多线程速度在我的代码中效率不高?

问题描述

由于某些原因,多线程在我的代码中效率不高。

我的代码从 txt 文件中获取一个令牌,并使用该令牌发送一个发布请求。

而且我不明白为什么多线程在我的代码中效率不高。

发出 3 个 post 请求需要 2.7 秒。

这是我的代码:

import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from time import time
url_list = [
    "https://www.google.com/api/"
]

tokens = set()
with open("tokens.txt", "r") as f:
    file_lines = f.readlines()
    for line in file_lines:
        tokens.add(line.strip())

token_data = {"token": None}
def makerequest(url):
    for token in tokens:
        token_data["Token"] = token
        html = requests.post(url,stream=True, data=token_data)
        print(html.text)

start = time()

processes = []
with ThreadPoolExecutor(max_workers=200) as executor:
    for url in url_list:
        processes.append(executor.submit(makerequest, url))

for task in as_completed(processes):
    print(task.result())


print(f'Time taken: {time() - start}')

2.7 秒发送 3 个 post 请求我不认为这对多线程有好处。

标签: pythonmultithreadingpython-requests

解决方案


ThreadPoolExecutor 对您提交给它的可调用对象没有任何特殊的洞察力或控制权。它不能改变他们的行为方式。它可以做的是在彼此不同的线程上启动传递给它的可调用对象让我们看一下您的示例:

您有一个 URL 和一定数量的令牌。每次调用makerequest都会发出一系列请求,每个请求在前一个完成后开始,每个令牌一个。它不以任何方式使用多线程——无论makerequest调用什么线程,它都是发出所有请求的线程,一个接一个。

每个 URL 循环一次——也就是说,你只执行一次(因为你只有一个 URL)——然后调用executor.submit,告诉它调用makerequest那个特定的 URL。它可以在线程池中的一个线程上执行此操作,但是因为您只告诉它进行一次调用,所以它只会使用一个线程。该单个线程将调用makerequest一次,并且该调用makerequest将在同一个线程上一个接一个地发出许多请求。

如果您希望并行发出请求,则需要进一步分解。例如,您可以从内部提取循环makerequest并使其采用 URL令牌。然后,您可以将 URL 和令牌的每个单独组合分别提交给执行程序。作为一个粗略的例子:

def makerequest(url, token):
    token_data = {"token": token}
    html = requests.post(url,stream=True, data=token_data)
    print(html.text)

# ...

processes = []
with ThreadPoolExecutor(max_workers=200) as executor:
    for url in url_list:
        for token in tokens:
            processes.append(executor.submit(makerequest, url, token))

小注:您使用"token""Token"可互换地作为字典中的键。这是混淆的秘诀——你应该弄清楚哪个是正确的并坚持下去。您还可以创建一个全局变量token_data,然后在makerequest. 这对线程来说是灾难性的——你不能保证一个线程不会在另一个线程使用它时修改它。您不应该修改线程之间共享的数据结构 - 而是每次都创建一个新的 token_data 作为局部变量。


推荐阅读