Python自动化学习笔记(十)——多进程,多线程,异常处理,faker模块,sys模块,jsonpath模块
1.多线程
1.1多线程创建和启动
- 进程:一些资源的集合
- 线程:程序执行的最小单位
- 线程包含在进程内,进程是由若干线程组成的,一个进程至少有一个线程。
- 多任务可以由多进程完成,也可以由一个进程内的多线程完成。
启动一个线程就是把一个函数传入并创建Thread
实例,然后调用start()
开始执行,循环创建线程时,应当全部创建完毕后,再循环每一个线程执行t.join,否则和串行效率就一样了,代码示例:
import threading import time def run(): time.sleep(1) print('run.............') starttime=time.time() threads=[] for i in range(20):#循环创建20个线程 t1=threading.Thread(target=run,) #实例化一个线程 threads.append(t1) t1.start()#启动线程 # for t in threads:#循环每一个线程并t.join来等待 # t.join() #主线程等待子线程执行结束 while threading.active_count()!=1: pass endtime=time.time() print(endtime-starttime)
一个多线程下载图片的例子如下
两个知识点:
- 多线程运行时拿不到函数的返回值,可以定义一个全局变量,把返回值存储到全局变量中
- 实例化线程时,函数运行的参数可以通过一个list传入,t=threading.Thread(target=download_pic,args=(url,))
import requests from hashlib import md5 import threading import time filename=[] def download_pic(url): r=requests.get(url) file_name=md5(r.content).hexdigest() #文件内容md5后的字符串拿来当作文件名 with open(file_name+'.jpg','wb')as fw: fw.write(r.content) filename.append(file_name) #多线程运行时拿不到函数的返回值,可以定义一个全局变量,把返回值存储到全局变量中 urls = [ 'https://cn.bing.com/az/hprichbg/rb/GoldenEagle_ZH-CN2823955379_1920x1080.jpg', 'https://cn.bing.com/az/hprichbg/rb/GoldenEagle_ZH-CN2823955379_1920x1080.jpg', 'https://cn.bing.com/az/hprichbg/rb/NapoleonsHat_ZH-CN2968205603_1920x1080.jpg', 'https://cn.bing.com/az/hprichbg/rb/Snowkiters_ZH-CN3098762517_1920x1080.jpg' ] start_time=time.time() #单线程下载 # for url in urls: # download_pic(url) #多线程下载 for url in urls: t=threading.Thread(target=download_pic,args=(url,)) t.start() while threading.active_count()!=1: pass end_time=time.time() print('下载完成,下载时间为%s'%(end_time-start_time)) print('下载图片文件名称分别为:',filename)
2.2 锁
确保一个线程在修改一个参数时
,别的线程一定不能改,我们可以给这个参数加一把锁,修改完毕后再释放锁
import threading count=0 lock=threading.Lock() #申请一把锁,多个线程操作同一个数据时,要加锁 def run(): global count with lock: #加锁,python3会自动加锁 count+=1 for i in range(10): t=threading.Thread(target=run,) t.start() while threading.active_count()!=1: pass print(count)
不写with lock的话,加锁和释放锁的方法分别是: lock.acquire()和
lock.release()
2.3守护线程
#守护线程:守护主线程,主线程执行完成后子线程立即结束 import threading import time def run(): time.sleep(5) print('run...') for i in range(100): puren=threading.Thread(target=run) puren.setDaemon(True)#设置子线程为守护线程 puren.start() print('over')
输出如下,子线程的run方法还没有执行就结束了,因为主线程结束了,所以守护线程立即结束
2.多进程
在Python中,多个线程也只能利用一个cpu核心,如果想要实现多核任务,把每个cpu核心都利用起来,只能使用多进程来实现。通常我们可以利用多线程来执行IO密集型任务,多进程来执行CPU密集型任务
下面的例子演示了循环启动多个子进程并等待其结束:
import multiprocessing import time def run(): time.sleep(2) print('run...') if __name__ == '__main__': for i in range(10): p=multiprocessing.Process(target=run) #实例化一个进程 p.start() #启动一个进程 while multiprocessing.active_children():#等待其他子进程运行完毕 pass
多进程传入调用函数参数的方法和多线程的一致,p=multiprocessing.Process(target=run,args=(url,))
3.异常处理
3.1 try-except
语法示例如下:
d={} l=[] try: print(d['name']) print(l[-1]) except KeyError as e: #多个异常,多个except print('字典里没有这个key',e) except IndexError as e: print('出错了,下标越界',e) except Exception as e: #捕捉所有异常 print('出现异常了',e) else: #没有出现异常时 print('没有异常') finally: print('finally')
ps:finally里的语句一定会执行
3.2 自定义异常
class NumberError(Exception): #定义一个异常类,继承Exception pass class M: def Main(self): count=input('请输入要产生多少条银行卡号') if not count.isdigit(): raise NumberError #抛出一个异常 for i in range(int(count)): self.card() m=M() m.Main()
输出为:
4.sys.argv
通过sys模块下的argv属性,可以获取运行python文件的时候传入的参数,代码示例:
import sys print(sys.argv) #获取运行python文件的时候传入的参数 if len(sys.argv)>1: if sys.argv[1]=='--help': quit('这个python是用来测试的,运行的时候需要使用python a.py port') else: port=sys.argv[1]else: port=7878 import flask server = flask.Flask(__name__) @server.route('/') def index(): return '<h1>首页</h1>' server.run(port=port)
以上代码,如果运行Python文件时输入:python sys模块.py 8888,则启动接口的端口为8888,如下图所示,不添加参数,默认启动,则端口为7878,传入多个参数时,用空格隔开
在pycharm运行代码时,在下图位置设置参数,再运行,也可以将参数传入
5.faker模块
faker模块是一个很强大的外部模块,可以生成各种数据,例如身份证号,电话号码,人名,地址等。示例:
from faker import Faker f=Faker(locale='zh_CN') #实例化 print(f.name()) #人名 print(f.postcode())#邮编 print(f.credit_card_number()) #身份证号 print(f.ssn())#身份证号 print(f.ipv4()) #ip地址 print(f.password()) #密码 print(f.address()) #地址 print(f.user_name()) #用户名
6.jsonpath
利用jsonpath模块可以快速找到json字典里的key,字典内有多重嵌套时非常好用,示例如下:
d={ "error_code": 0, "stu_info": [ { "id": 2059, "name": "小白", "sex": "男", "age": 28, "addr": "河南省济源市北海大道32号", "grade": "天蝎座", "phone": "18378309272", "gold": 10896, "info":{"card":23333,"bank_name":"中国银行"} }, { "id": 2067, "name": "小名", "sex": "男", "age": 28, "addr": "河南省济源市北海大道32号", "grade": "天蝎座", "phone": "12345678915", "gold": 100 }, { "id": 2086, "name": "小红", "sex": "男", "age": 28, "addr": "河南省济源市北海大道32号", "grade": "狮子座", "phone": "15837627044", "gold": 4040 }, { "id": 2095, "name": "小懒", "sex": "男", "age": 24, "addr": "河南省项城市秣陵镇", "grade": "摩羯座", "phone": "13608417301", "gold": 100 }, { "id": 2107, "name": "小黑", "sex": "女", "age": 10, "addr": "河南省康定大道158号", "grade": "水瓶座", "phone": "17612227885", "gold": 700 }, { "id": 2142, "name": "小允", "sex": "男", "age": 24, "addr": "河南省项城市秣陵镇", "grade": "摩羯座", "phone": "13608417304", "gold": 100 }, { "id": 2240, "name": "小黄", "sex": "男", "age": 28, "addr": "深圳市南山区", "grade": "天蝎座", "phone": "12456785512", "gold": 100 } ] } import jsonpath res=jsonpath.jsonpath(d,'$.stu_info[0].info.bank_name') print(res) res=jsonpath.jsonpath(d,'$..bank_name') #查找内部key,存在的话返回key的value,不存在返回false print(res) res=jsonpath.jsonpath(d,'$..error_code') #查找内部key,存在的话返回key的value,不存在返回false print(res) res=jsonpath.jsonpath(d,'$..bakkk') #查找内部key,存在的话返回key的value,不存在返回false print(res)
输出结果为: