线程并行使用线程池并发操作 2800 多条线程,时间反而用时比不用线程池更大?原因是什么?

参考文章:
11.4. threading — 管理单个进程里的并行操作

我们地excel数据集:

Python

使用threading,单进程多线程操作

threading — 管理单个进程里的并行操作

管理几个线程执行。
使用线程允许一个程序在同一个进程空间中并发运行多个操作。单进程多线程操作。

主要在excel2sql.py文件中进行修改:

多线程操作主要部分代码:

    def insert_coordinates(
        self, 
    ) -> "result={'code':'xx','message':'xx','data':xx}":
        geo_app = Geo_mapInterface(config.geo_key)
        all_data = [self.sh_data.row_values(i) for i in range(self.rows)]
        test_data = [i for i in all_data ]
        print(test_data)
        new_excel = copy(self.excel)
        ws = new_excel.get_sheet(self.sheet)
        def test(i):
            cur_coordinates = 12345
            ws.write(i,3,cur_coordinates)
            time.sleep(0.01)
            # print(i,l[2],'经纬度为',cur_coordinates,"已存入exlcel文档")
        for i,l in enumerate(test_data[:]):
            if l[3] and i!=0:
                print(test[0][3],"已经存在",i[3])
            elif l[3]!=" ":
                # cur_coordinates = geo_app.get_coordinatesViaaddress(i[1])
                test(i)
                # t = threading.Thread(target=test, args=(i,))
                # t.start()
        new_excel.save(config.src_path+'\\data\\new_fileName.xls')

我们使用threading来并行运行多个线程:

                # cur_coordinates = geo_app.get_coordinatesViaaddress(i[1])
                # test(i)
                t = threading.Thread(target=test, args=(i,))
                t.start()

两者时间分别是30.804279s和00.643780s

我丢你吗,这尼玛是真的离谱!( ఠൠఠ )ノ

尝试使用线程池--concurrent.futures模块来开发线程并行:

# 线程池
from concurrent.futures import ThreadPoolExecutor

import好我们要的线程池
我们来试一下将2800多个线程装在线程池中运行:

        def test(i):
            cur_coordinates = 12345
            ws.write(i,3,cur_coordinates)
            time.sleep(0.01)
            if i ==2865:
                print('最后一条数据我运行完了',i,datetime.datetime.now())
            # print(i,l[2],'经纬度为',cur

        executor = ThreadPoolExecutor(max_workers=3)
        for i,l in enumerate(test_data):
            if l[3] and i!=0:
                print(test[0][3],"已经存在",i[3])
            elif l[3]!=" ":
                # cur_coordinates = geo_app.get_coordinatesViaaddress(i[1])
                # print(os.cpu_count())
                # 单进程单线程30.804279stest
                # test(i)

                # 利用线程池--concurrent.futures模块来管理多线程:
                future = executor.submit(test,i)

                # 单进程,8核CPU,线程并行00.743780s,
                # t = threading.Thread(target=test, args=(i,))
                # t.start()
                # print(t.getName())
                # 
        new_excel.save(config.src_path+'\\data\\new_fileName.xls')

当整个当前线程(当前文件运行完毕后)

if __name__ == "__main__":
    test = OpExcel(config.src_path+"\\data\\2019最新全国城市省市县区行政级别对照表(194).xls","全国城市省市县区域列表")
    # print(test.init_SampleViaProvince_name("北京市"))
    start = datetime.datetime.now()
    print("开始运行",start)
    test.insert_coordinates()
    print(datetime.datetime.now() - start)
    print(datetime.datetime.now())

我们是会打印当前时间的,但是当当前线程运行完成,似乎装在线程池的代码还没运行完毕,我们看看运行后的结果:

(env) PS F:\workspace> & f:/workspace/env/Scripts/python.exe f:/workspace/城市距离爬取/process_data/excel2sql.py
开始运行 2019-12-29 16:29:06.819023
0:00:00.166542
2019-12-29 16:29:06.985565
最后一条数据我运行完了 2865 2019-12-29 16:29:17.244969

以上代码实际运行完毕的时间应该是 17.244969 - 06.819023,大约为10s

而我们利用同样的代码来运行之前的简单的单进程多线程并行,运行结果:

(env) PS F:\workspace> & f:/workspace/env/Scripts/python.exe f:/workspace/城市距离爬取/process_data/excel2sql.py
开始运行 2019-12-29 16:30:16.586423
最后一条数据我运行完了 2865 2019-12-29 16:30:17.172863
0:00:00.632285
2019-12-29 16:30:17.218708

全部运行完毕的时间大概是16:30:17.218708 - 16:30:16.586423,也就是0.6s左右。

是因为线程池的大小缘故吗?
我们试着将线程池大小增大一倍:

executor = ThreadPoolExecutor(max_workers=6)

运行结果:

(env) PS F:\workspace> & f:/workspace/env/Scripts/python.exe f:/workspace/城市距离爬取/process_data/excel2sql.py
开始运行 2019-12-29 16:32:09.525962
0:00:00.176528
2019-12-29 16:32:09.702490
最后一条数据我运行完了 2865 2019-12-29 16:32:14.756947

确实有影响,那是不是可以判定影响运行速度的原因就是线程池的大小呢?
照这样说,反而将2800多个线程不放在池里不会就更快,更方便吗。
线程池的作用本来就是,方便上下文管理。。是不是这样的操作就是相当于用更多的时间来换取更安全的操作(上下文,资源管理)?

文章!!首发于我的博客Stray_Camel(^U^)ノ~YO
讨论数量: 5

@Jason990420

于由用户指出自问自答的模式(还奖励5个声望)的问题:

我昨天 12点给网站站长发了微信!这是一个bug,我也才发现。(和站长联系了这不是bug,问答:用户自问自答并选为答案,是否应该给与声望奖励?) 不过如果发现恶意刷分可以举报!

Python

无辜躺枪🙃

4年前 评论
Summer 4年前
Jason990420

我是看Stray_camel发了一个问题, 不到一个小时就自己找到答案, 立刻标示为最佳答案. 能否代表没确认自己能找到答案, 而随意发问 ?

4年前 评论
娃哈哈店长 (楼主) 4年前
Jason990420

没啥意见, 只是看有人发了个问题, 想提供协助, 看了半天内容, 最后结果感觉自己多此一举, 早知道就不花时间去看.

4年前 评论
娃哈哈店长 (楼主) 4年前
娃哈哈店长 (楼主) 4年前
Jason990420

不是声望分的问题, 如果是别人发文, 我还可以选择性地看或不看; 但是如果是发问题, 我就会花时间去看内容, 想提供帮助, 看了内容又看到发文者自己有了答案, 自然会想到, 喔....原来发文者不需要协助, 自己能找到答案, 早知道就不花时间去看了.

4年前 评论

感觉应该是设置这个并行池的时候的问题、毕竟相当于一个容器装起来 容器建立、之类的操作都需要时间,但是并发池肯定更放便管理。应该就是这个理儿了 🙃。解答完毕! 估计就是这样子了,有兴趣的看这篇问答来研究一下呗。问答:问答:如何合理地估算线程池大小?N 为 CPU 核数,2N+1/N+1 公式是怎么来的...

后面我又测试了一下,当我们设置线程池的大小为100的时候或者用BoundedSemaphore设置线程数量,两种情况下还是线程池相对的优化好些。。!个人觉得是当对线程进行操作时比如传参、控制量等,会涉及到更多的上下文操作。线程池的优化就很好的体现了。。在日常的开发中,我们还是用线程池比较好!

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!