在 python 中同时调用 api
calling an api concurrently in python
我需要与 api 交谈以获取有关团队的信息。每个团队都有一个唯一的 ID。我用那个 id 调用 api,我得到了每支球队的球员名单(dicts 名单)。玩家的键之一是另一个 id,我可以用它来获取有关该玩家的更多信息。我可以捆绑所有这些 player_ids 并调用 api 以在一个 api 调用中获取每个玩家的所有附加信息。
我的问题是:
我预计团队的数量会增加,可能会很大。还有,每支队伍的人数也可以增加。
同时对 api 进行这些 api 调用的最佳方法是什么?我可以使用 multiprocessing.dummy 中的 ThreadPool,我也看到 genvent 用于类似这样的事情。
对 api 的调用需要一些时间才能获得 return 值(每次批量 api 调用需要 1-2 秒)。
现在,我做的是:
for each team:
get the list of players
store the player_ids in a list
get the player information for all the players (passing the list of player_ids)
assemble and process the information
如果我使用 ThreadPool,我可以执行以下操作:
create a ThreadPool of size x
result = pool.map(function_to_get_team_info, list of teams)
pool.close()
pool.join()
#process results
def function_to_get_team_info(team_id):
players = api.call(team_id)
player_info = get_players_information(players)
return player_info
def get_players_information(players):
player_ids = []
for player in players:
player_ids.append(player['id'])
return get_all_player_stats(player_ids)
def get_all_player_stats(players_id):
return api.call(players_id)
这会同时处理每个团队,并将所有信息组合到线程池结果中。
为了使其完全并发,我想我需要使我的 ThreadPool 的大小与团队的数量相同。但我不认为这可以很好地扩展。所以,我想知道我是否使用 gevent 来处理这些信息是否是更好的方法。
非常欢迎任何建议
一个解决方案是:
- 准备要执行的任务列表,在您的案例中是要处理的团队 ID 列表,
- 创建 N 个线程工作者的固定池,
- 每个工作线程从列表中弹出一个任务并处理该任务(下载团队数据),完成后弹出另一个任务,
- 当任务列表为空时,工作线程停止。
此解决方案可以使您免受特定团队的处理需要例如100个时间单位,当其他团队在1个时间单位处理(平均)。
您可以根据团队数量、平均团队处理时间、CPU 核心数量等调整线程工作者的数量。
扩展答案
这可以通过 Python multiprocessing.Pool
:
来实现
from multiprocessing import Pool
def api_call(id):
pass # call API for given id
if __name__ == '__main__':
p = Pool(5)
p.map(api_call, [1, 2, 3])
我需要与 api 交谈以获取有关团队的信息。每个团队都有一个唯一的 ID。我用那个 id 调用 api,我得到了每支球队的球员名单(dicts 名单)。玩家的键之一是另一个 id,我可以用它来获取有关该玩家的更多信息。我可以捆绑所有这些 player_ids 并调用 api 以在一个 api 调用中获取每个玩家的所有附加信息。
我的问题是: 我预计团队的数量会增加,可能会很大。还有,每支队伍的人数也可以增加。
同时对 api 进行这些 api 调用的最佳方法是什么?我可以使用 multiprocessing.dummy 中的 ThreadPool,我也看到 genvent 用于类似这样的事情。
对 api 的调用需要一些时间才能获得 return 值(每次批量 api 调用需要 1-2 秒)。
现在,我做的是:
for each team:
get the list of players
store the player_ids in a list
get the player information for all the players (passing the list of player_ids)
assemble and process the information
如果我使用 ThreadPool,我可以执行以下操作:
create a ThreadPool of size x
result = pool.map(function_to_get_team_info, list of teams)
pool.close()
pool.join()
#process results
def function_to_get_team_info(team_id):
players = api.call(team_id)
player_info = get_players_information(players)
return player_info
def get_players_information(players):
player_ids = []
for player in players:
player_ids.append(player['id'])
return get_all_player_stats(player_ids)
def get_all_player_stats(players_id):
return api.call(players_id)
这会同时处理每个团队,并将所有信息组合到线程池结果中。
为了使其完全并发,我想我需要使我的 ThreadPool 的大小与团队的数量相同。但我不认为这可以很好地扩展。所以,我想知道我是否使用 gevent 来处理这些信息是否是更好的方法。
非常欢迎任何建议
一个解决方案是:
- 准备要执行的任务列表,在您的案例中是要处理的团队 ID 列表,
- 创建 N 个线程工作者的固定池,
- 每个工作线程从列表中弹出一个任务并处理该任务(下载团队数据),完成后弹出另一个任务,
- 当任务列表为空时,工作线程停止。
此解决方案可以使您免受特定团队的处理需要例如100个时间单位,当其他团队在1个时间单位处理(平均)。
您可以根据团队数量、平均团队处理时间、CPU 核心数量等调整线程工作者的数量。
扩展答案
这可以通过 Python multiprocessing.Pool
:
from multiprocessing import Pool
def api_call(id):
pass # call API for given id
if __name__ == '__main__':
p = Pool(5)
p.map(api_call, [1, 2, 3])