python - 为什么多线程速度在我的代码中效率不高?
问题描述
由于某些原因,多线程在我的代码中效率不高。
我的代码从 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 请求我不认为这对多线程有好处。
解决方案
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 作为局部变量。
推荐阅读
- postgresql - Prisma 模型自引用(一对多)
- python - 将列的值(值列表)转换为列名并放入 1
- flutter - Flutter null 安全问题是:未为“Object”类型定义运算符“[]”
- php - php curl blob 发送文件 multipart/form-data 谁能给出正确的解决方案?
- java - 在这种情况下我应该使用哪一种模式或存储库模式?
- java - 使用 OpenRewrite 超类访问检查将 Micronaut 2.X 升级到 3.X 失败
- robotframework - 如何在 Pycharm 的 Robot 框架测试中放置调试/断点?
- javascript - 无法在 javascript 中设置属性
- linux - 如何在 Linux 机器上设置对 JMeter 负载测试的监控?
- flutter - Flutter 垂直 PageView 动态高度