线程并行使用线程池并发操作 2800 多条线程,时间反而用时比不用线程池更大?原因是什么?
参考文章:
11.4. threading — 管理单个进程里的并行操作
我们地excel数据集:
使用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多个线程不放在池里不会就更快,更方便吗。
线程池的作用本来就是,方便上下文管理。。是不是这样的操作就是相当于用更多的时间来换取更安全的操作(上下文,资源管理)?
@Jason990420
于由用户指出自问自答的模式(还奖励5个声望)的问题:
我昨天 12点给网站站长发了微信!
这是一个bug,我也才发现。(和站长联系了这不是bug,问答:用户自问自答并选为答案,是否应该给与声望奖励?) 不过如果发现恶意刷分可以举报!无辜躺枪🙃我是看Stray_camel发了一个问题, 不到一个小时就自己找到答案, 立刻标示为最佳答案. 能否代表没确认自己能找到答案, 而随意发问 ?
没啥意见, 只是看有人发了个问题, 想提供协助, 看了半天内容, 最后结果感觉自己多此一举, 早知道就不花时间去看.
不是声望分的问题, 如果是别人发文, 我还可以选择性地看或不看; 但是如果是发问题, 我就会花时间去看内容, 想提供帮助, 看了内容又看到发文者自己有了答案, 自然会想到, 喔....原来发文者不需要协助, 自己能找到答案, 早知道就不花时间去看了.
感觉应该是设置这个并行池的时候的问题、毕竟相当于一个容器装起来 容器建立、之类的操作都需要时间,但是并发池肯定更放便管理。应该就是这个理儿了 🙃。解答完毕! 估计就是这样子了,有兴趣的看这篇问答来研究一下呗。问答:问答:如何合理地估算线程池大小?N 为 CPU 核数,2N+1/N+1 公式是怎么来的...
后面我又测试了一下,当我们设置线程池的大小为100的时候或者用BoundedSemaphore设置线程数量,两种情况下还是线程池相对的优化好些。。!个人觉得是当对线程进行操作时比如传参、控制量等,会涉及到更多的上下文操作。线程池的优化就很好的体现了。。在日常的开发中,我们还是用线程池比较好!