Python中两种多线程实现方式对比

前言

  实习期间需要用到python多线程,先后使用了threading和ThreadPoolExecutor两个模块,因此简单记录一下。

一、使用需求

  公司项目需要增加一个多个设备同时升级的接口,接口接收的参数是多台设备的相关信息,为了提高升级效率,需要开启多线程去做升级操作。

二、ThreadPoolExecutor实现

参考:
  [python] ThreadPoolExecutor线程池
  as_completed函数用例

1. 主要代码


	with ThreadPoolExecutor(max_workers=20) as executor:
	     for device in devices['devices']:
	         device['reboot_dev']=reboot_dev
	         device['testCycleId']=testCycleId
	         device['firmware_type']=firmware_type
	         device['task_id']=str(task_id)
	         task = executor.submit(device_upgrade, **device)
	         task_list.append(task)
	         
	     # #as_completed按完成顺序返回,不按添加顺序遍历
	     # for future in as_completed(task_list):    
	        #     # print("future:",future.__dict__)
	        #     print("result:",future.result())
	        #     if future.result()['success']==False:
	        #         msg_dicts.append(dict(success='False',ip=devices['devices'][index]['ip'],msg=future.result()['msg']))
	        #         flag=False
	        #     else:
	        #         msg_dicts.append(dict(success='True',ip=devices['devices'][index]['ip'],msg=future.result()['msg']))
	        #     index+=1
	        
		 #按添加顺序遍历
	     for future in task_list:    
	         # print("future:",future.__dict__)
	         print("result:",future.result())
	         if future.result()['success']==False:
	             msg_dicts.append(dict(success=False,ip=devices['devices'][index]['ip'],msg=future.result()['msg']))
	             flag=False
	         else:
	             msg_dicts.append(dict(success=True,ip=devices['devices'][index]['ip'],msg=future.result()['msg']))
	         index+=1

2.小结

  concurrent.futures模块使用起来十分简洁方便,ThreadPoolExecutor 是线程池执行者,相较于多开线程能够有更好的效率,不使用as_completed是按添加顺序遍历执行结果,使用as_completed这个生成器,实现先完成先处理,可以进一步提高效率。

三、threading实现

参考:Python中的多线程

1.引入原因

  原本按照ThreadPoolExecutor的方法能够实现多线程,但是由于每次多线程升级时,cpu会跑满,导致FastApi项目自动重启,重启后会接着升级,但此期间接口会返回502,所以利用redis将升级日志存储起来,不等升级完成直接返回结果,新建一个接口去读取redis存储的实时升级日志。
  但是在尝试用下面代码实现时,发现还是会阻塞主线程(也有可能是我使用方法不对):

	with ThreadPoolExecutor(max_workers=20) as executor:
		for device in devices['devices']:
			device['reboot_dev']=reboot_dev
			device['testCycleId']=testCycleId
			device['firmware_type']=firmware_type
			device['task_id']=str(task_id)
			task = executor.submit(device_upgrade, **device)
			task_list.append(task)
	return {"success":True,"msg":"正在升级中..."}

  因此,尝试换种方法来实现,也就是使用threading模块。

2.主要代码

	for device in devices['devices']:
        device['reboot_dev']=reboot_dev
        device['testCycleId']=testCycleId
        device['firmware_type']=firmware_type
        device['task_id']=str(task_id)
        task = threading.Thread(target=device_upgrade, args=(None,device['ip'],device['port'],device['username'],device['password'],device['reboot_dev'],"","","","","","","","",device['testCycleId'],device['firmware_type'],device['task_id']))
        task.start()
        redis_conn.hset(str(task_id), device['ip'], "begin")
        print(device['ip'],"beginning!!!")
        first_log=redis_conn.hget(str(task_id),'log')
        print(first_log)
        if str(first_log)=="None":
            redis_conn.hset(str(task_id),'log',datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m-%d %H:%M:%S')+ " IP:"+device['ip']+" 开始升级\n")
        else:
            redis_conn.hset(str(task_id),'log',str(redis_conn.hget(str(task_id),'log'))+datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m-%d %H:%M:%S')+ " IP:"+device['ip']+" 开始升级\n") 
    return {"success":True,"msg":"正在升级中..."}

3.小结

  threading模块的实现方法是用一个for循环依次start线程,这样的方法相较于线程池效率会有所降低,但是能够不阻塞主线程,在主线程结束后,子线程依然能够执行下去,能够越过资源不足的问题。

四、总结

  此次实现多线程的两种方式中,主要推荐线程池的方式去执行批量的任务,但是由于我使用线程池的方法无法满足项目需求(有哪位大佬指点一下咋实现),所以换为threading模块实现。
  本次也算是和Python多线程打了交道,感觉自己还是有很多东西不会,继续加油吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值