如何控制python的ThreadPoolExecutor的吞吐速度?

时间:2018-04-04 07:46:30

标签: python python-2.7 python-multithreading concurrent.futures

我正在使用python的concurrent.futures ThreadPoolExecutor启动异步任务。 在this方法之后,我使用tqdm进度条监控异步调用的进度。

我的代码看起来像这样

with concurrent.futures.ThreadPoolExecutor(max_workers = n_jobs) as executor:
    future_to_url = {executor.submit(target_function, URL): URL for URL in URL_list}
    kwargs = {'total': len(future_to_url), # For tqdm
            'unit': 'URL',                 # For tqdm
            'unit_scale': True,            # For tqdm
            'leave': False,                # For tqdm
            'miniters': 50,                # For tqdm
            'desc': 'Scraping Progress'}
    for future in tqdm(concurrent.futures.as_completed(future_to_url), **kwargs):
            URL = future_to_url[future]
            try:
                data = future.result()     # Concurrent calls
            except Exception as exc:
                error_handling()           # Handle errors
            else:
                result_handling()          # Handle non-errors

控制台输出如下所示

Scraping Progress:   9%|▉  | 3.35k/36.2k [08:18<1:21:22, 6.72URL/s] # I want < 6/s
Scraping Progress:   9%|▉  | 3.40k/36.2k [08:26<1:21:16, 6.72URL/s] # I want < 6/s
Scraping Progress:  10%|▉  | 3.45k/36.2k [08:30<1:20:40, 6.76URL/s] # I want < 6/s
Scraping Progress:  10%|▉  | 3.50k/36.2k [08:40<1:20:51, 6.73URL/s] # I want < 6/s
Scraping Progress:  10%|▉  | 3.55k/36.2k [08:46<1:20:36, 6.74URL/s] # I want < 6/s
Scraping Progress:  10%|▉  | 3.60k/36.2k [08:52<1:20:17, 6.76URL/s] # I want < 6/s

我知道我可以设置一个URL队列并控制其大小,如here所述。

但是,我不知道如何控制吞吐速度本身。假设我希望每秒不超过6个URL。除了在上面的例子中将time.sleep(n)投入target_function()之外,这可以归档吗?

如何在python的 ThreadPoolExecutor中有效控制 concurrent.futures 的吞吐速度?

1 个答案:

答案 0 :(得分:2)

很快回答,没有这样的方法。声明池后,如果没有先关闭池并重新创建池,则无法更改工作线程数。也没有办法让池提要任务慢于工人的最高速度。

你有几个(不太理想)的选择。

一种是将基于全局变量的睡眠添加到工作者。然后,您可以使用任务完成的回调来测量实际速度并相应地调整变量。但如果睡眠不成问题,这是行不通的。

更好的,尽管更繁重的方式是自己编写任务管理器。在此版本中,您不使用池,而是编写一个管理工作进程的类。你产生足够的&#34;足够的&#34;工人和工人听队列完成任务。您将以所需的速度从您的经理提供此队列。您将队列设置为具有非常低的最大大小,如果您的经理检测到队列已满,则会生成另一个工作队员。

但是没有内置功能可以做你想做的事情,这意味着需要一些工作,或者你需要重新设计你的程序,以便你不会一次性将所有任务都提供给池,而是做一些限制那里。