为什么在使用ThreadPoolExecutor时并发不起作用?

时间:2019-09-05 08:56:28

标签: python pandas concurrency python-multiprocessing python-multithreading

我正在编写一个应用程序,用于将excels(有几张纸,7-10MB,约15万行)中的数据插入数据库。我用

解析excels

pandas.read_excel,我想减少等待解析大文件或文件列表的时间。以下代码可以完成这项工作:

# coding : utf-8

import pandas as pd
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor


def meta_job(filename):

    num = int(filename[3])
    print(datetime.now().strftime("[%H:%M:%S:%f]"), end=' ')
    print('%smeta_job(%d) start' % (' ' * num, num))

    _ = pd.read_excel(filename, sheet_name=None)

    print(datetime.now().strftime("[%H:%M:%S:%f]"), end=' ')
    print('%smeta_job(%d) end' % (' ' * num, num))
    return filename


def main(fileNames):
    executor = ThreadPoolExecutor(max_workers=8)
    results = executor.map(meta_job, fileNames)
    for i, res in enumerate(results):
        print(i, res)

if __name__ == "__main__":
    fileNames = ["d[%d]_full_10.xlsx" % i for i in range(8)]
    main(fileNames)

    # do the parse with for loop
    print("*" * 20)
    for i in fileNames:
        meta_job(i)


问题是,当我运行上述代码时,并发方法和for循环几乎同时使用,而更糟糕的是for循环使用的时间少于并发。

但是,当我将ThreadPoolExecutor更改为ProcessPoolExecutor时,并发变得更快(30秒而不是2分钟)。以下是输出。

  • ProcessPoolExecutor输出
[16:46:38:506226] meta_job(0) start
[16:46:38:586626]   meta_job(2) start
[16:46:38:606732]    meta_job(3) start
[16:46:38:775630]        meta_job(7) start
[16:46:38:654980]     meta_job(4) start
[16:46:38:659215]      meta_job(5) start
[16:46:38:727387]       meta_job(6) start
[16:46:38:534345]  meta_job(1) start
[16:47:03:936892]      meta_job(5) end
[16:47:04:127832]  meta_job(1) end
[16:47:05:585193] meta_job(0) end
0 d[0]_full_10.xlsx
1 d[1]_full_10.xlsx
[16:47:07:104038]     meta_job(4) end
[16:47:10:099222]   meta_job(2) end
2 d[2]_full_10.xlsx
[16:47:10:867077]    meta_job(3) end
3 d[3]_full_10.xlsx
4 d[4]_full_10.xlsx
5 d[5]_full_10.xlsx
[16:47:11:305149]       meta_job(6) end
6 d[6]_full_10.xlsx
[16:47:11:392175]        meta_job(7) end
7 d[7]_full_10.xlsx
********************
[16:47:11:396162] meta_job(0) start
[16:47:25:603109] meta_job(0) end
[16:47:25:603109]  meta_job(1) start
[16:47:38:163148]  meta_job(1) end
[16:47:38:163148]   meta_job(2) start
[16:47:55:602426]   meta_job(2) end
[16:47:55:602426]    meta_job(3) start
[16:48:12:402708]    meta_job(3) end
[16:48:12:404835]     meta_job(4) start
[16:48:26:275334]     meta_job(4) end
[16:48:26:275334]      meta_job(5) start
[16:48:38:156112]      meta_job(5) end
[16:48:38:156112]       meta_job(6) start
[16:48:54:135494]       meta_job(6) end
[16:48:54:138486]        meta_job(7) start
[16:49:10:548779]        meta_job(7) end
  • ThreadPoolExecutor输出
[18:26:22:154206] meta_job(0) start
[18:26:22:154206]  meta_job(1) start
[18:26:22:154206]   meta_job(2) start
[18:26:22:154206]    meta_job(3) start
[18:26:22:157393]     meta_job(4) start
[18:26:22:157393]      meta_job(5) start
[18:26:22:158388]       meta_job(6) start
[18:26:22:159391]        meta_job(7) start
[18:28:41:549298]  meta_job(1) end
[18:28:45:378990]      meta_job(5) end
[18:28:56:916256]     meta_job(4) end
[18:28:57:436046] meta_job(0) end
0 d[0]_full_10.xlsx
1 d[1]_full_10.xlsx
[18:29:13:799117]    meta_job(3) end
[18:29:17:903461]        meta_job(7) end
[18:29:19:081831]       meta_job(6) end
[18:29:19:762531]   meta_job(2) end
2 d[2]_full_10.xlsx
3 d[3]_full_10.xlsx
4 d[4]_full_10.xlsx
5 d[5]_full_10.xlsx
6 d[6]_full_10.xlsx
7 d[7]_full_10.xlsx
********************
[18:29:19:767528] meta_job(0) start
[18:29:39:749447] meta_job(0) end
[18:29:39:752440]  meta_job(1) start
[18:29:56:921441]  meta_job(1) end
[18:29:56:923431]   meta_job(2) start
[18:30:19:906304]   meta_job(2) end
[18:30:19:909290]    meta_job(3) start
[18:30:43:297230]    meta_job(3) end
[18:30:43:299242]     meta_job(4) start
[18:31:02:185841]     meta_job(4) end
[18:31:02:188833]      meta_job(5) start
[18:31:19:322984]      meta_job(5) end
[18:31:19:324980]       meta_job(6) start
[18:31:42:272996]       meta_job(6) end
[18:31:42:275983]        meta_job(7) start
[18:32:05:544849]        meta_job(7) end

在另一个有关xlrd的问题中,我看到了一些答案。这是否意味着xlrd不支持并发(不发布GIL)?谢谢!

1 个答案:

答案 0 :(得分:1)

Pandas.read_excel使用xlrd来实际读取MS Excel文件。 xlrd source code是所有Python代码,因此将隐式始终包含GIL。因此,使用线程进行并发时不会看到太多的加速。还有一个用于读取MS Excel文件的openpyxl项目,但这似乎也是一个纯Python项目,因此具有类似的性能特征

如@JimNilsson所说,由于GIL被发布在低级文件IO代码(全都是本机C代码)中,因此您可能会得到一些并发性,但这并不太可能