day09进程与异常处理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了day09进程与异常处理相关的知识,希望对你有一定的参考价值。
异常处理
老师博客:http://www.cnblogs.com/linhaifeng/articles/6232220.html
异常组成:
Tracebace追踪信息(哪行出现了异常)、异常类型、异常的值
异常类型:
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
异常捕获到了以后判断是否是相关类型异常,如果是,执行except后面的代码
万能异常
try:
# int("nit")
print(ddd)
except Exception as e:
print(e)
Ps:不能捕捉到语法异常
什么时候要用异常?
s1 = ‘hello‘
try:
int(s1)
except IndexError as e:
print(e)
except KeyError as e:
print(e)
except ValueError as e:
print(e)
#except Exception as e:
# print(e)
else:
print(‘try内代码块没有异常则执行我‘)
finally:
print(‘无论异常与否,都会执行该模块,通常是进行清理工作‘)
主动触发异常
#_*_coding:utf-8_*_
__author__ = ‘Linhaifeng‘
try:
raise TypeError(‘类型错误‘)
except Exception as e:
print(e)
进程线程
进程:正在进行的一个过程或者说一个任务,一个正在执行的过程,cpu来做这个任务。Cpu同一时刻只能做一个任务。所谓的看到cpu多并发是进程的执行与切换。
并行:同时运行,只有具备多个cpu才能实现并行
并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
参数介绍:
group参数未使用,值始终为None
target表示调用对象,即子进程要执行的任务
args表示调用对象的位置参数元组,args=(1,2,‘egon‘,)
kwargs表示调用对象的字典,kwargs={‘name‘:‘egon‘,‘age‘:18}
name为子进程的名称
创建进程:
方法一
from multiprocessing import Process
import random
def eat(name):
print("%s want to eat" %name)
food = ["bananan","apple","malon","lemon","peach"]
print(random.choice(food))
if __name__ == ‘__main__‘:
p1 = Process(target=eat,args=("dodo",),name="eating")#复制进程创建新进程,("dodo",)这里一定要是一个元组
p1.start()
print("主进程")
输出结果:
主进程
dodo want to eat
Bananan
Ps:父进程打印完为什么还要等着主进程,就是打印控制台还没有关闭
如果父进程先结束,那么子进程就变成僵死进程,所以父进程一定要等着子进程。
方法二
class Eat(Process):
def __init__(self,name1,name="Process1"):
super().__init__()
self.name1 = name1
self.name=name
def run(self):#自己定义的Process的进程类,一定要写run方法,p.start就是在调用run方法
print("%s want to eat" % self.name1)
food = ["bananan","apple","malon","lemon","peach"]
print(random.choice(food))
if __name__ == ‘__main__‘:
p1 = Eat("dodo")
p1.start()
print("进程名:%s" %p1.name)
print("主进程")
输出结果:
进程名:Process1
主进程
dodo want to eat
Peach
Process的方法:
1、join()等待子进程运行结束,再向下执行
def eat(name):
print("%s want to eat" %name)
food = ["bananan","apple","malon","lemon","peach"]
print(random.choice(food))
if __name__ == ‘__main__‘:
p1 = Process(target=eat,args=("dodo",),name="eating")
p1.start()
p1.join()#等待子进程运行结束,再向下执行
print("主进程")
输出结果:
dodo want to eat
malon
主进程
Ps:先启动的进程不一定先执行,要看哪个进程先建完,哪个进程先执行
2、daemon守护进程
在p1.start()前写 p1.Daemon = True
父进程就可以终止子进程了,不需要等待子进程执行完
from multiprocessing import Process,JoinableQueue
import time,random
def consumer(q,name):
while True:
# time.sleep(random.randint(1,3))
res = q.get()
q.task_done()
# if res ==None:break
print("消费者%s,拿到了%s" %(name,res))
def product(seq,p,name):
for item in seq:
# time.sleep(random.randint(1, 3))
q.put(item)
print("%s生产了%s" %(name,item))
# q.put(None)#结束方式一
q.join()#方式二
print("============>zhujincheng")
if __name__ == ‘__main__‘:
q=JoinableQueue()
c= Process(target=consumer,args=(q,‘egon‘))
c.daemon=True#守护进程,主进程结束,子进程也结束
c.start()
seq = ["包子%s" %i for i in range(10)]
p= Process(target=consumer, args=(q, ‘egon‘))
product(seq,p,"dodo")
3、结束进程:
P1.terminate()
4、判断进程是否在
P1.is_alive
多进程实例
服务端:
from multiprocessing import Process
from socket import *
import logging
logging.basicConfig(level=20,
format=‘%(module)s - %(asctime)s - %(levelname)s : %(message)s‘,
datefmt=‘%Y-%m-%d %H:%M:%S %p‘,
handlers=[logging.FileHandler(‘server.log‘,encoding=‘utf-8‘,mode=‘a‘)])
soc = socket(AF_INET,SOCK_STREAM)
soc.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
soc.bind(("127.0.0.1",8080))
soc.listen(5)
# def talk(conn,addr):
# while True:
# try:
# msg = conn.recv(1024)
# if not msg:break
# logging.info("%s...发送消息【%s】" %(addr,msg.decode("utf-8")))
# conn.send(msg.upper())
# except Exception :
# break
def write(conn,addr,Filename):
while True:
try:
msg = conn.recv(1024)
if not msg:break
with open(Filename, ‘a‘, encoding="utf-8") as f:
f.write(msg.decode("utf-8")+"\\n")
logging.info("%s...写入文件%s,写入内容【%s】" % (addr, Filename, msg.decode("utf-8")))
conn.send("写入成功".encode("utf-8"))
except Exception :
break
if __name__ == ‘__main__‘:
while True:
conn,addr = soc.accept()#接受链接
logging.info("[%s]......链接" %conn)
# p = Process(target=talk,args=(conn,addr))
p = Process(target=write, args=(conn,addr,"a.txt"))
p.start()
客户端:1——n都是一样的客户端
from multiprocessing import Process
from socket import *
soc = socket(AF_INET,SOCK_STREAM)
soc.connect(("127.0.0.1",8080))
while True:
msg = input(">>>").strip()
if not msg:continue
soc.send(msg.encode("utf-8"))
res = soc.recv(1024)
print(res.decode("utf-8"))
IPC:进城之间通讯方式,基于消息
线程之间可以直接通信,进程必须使用ipc才能通讯
进程彼此之间互相隔离,要实现进程间通信,即IPC,multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的
Ipc是基于消息的通讯机制,管道和队列
队列就是管道加锁实现的。
队列:先进先出
堆栈:先进后出
from multiprocessing import Process,Queue
q = Queue(3)#放三个值
q.put(‘a‘)
q.put(‘b‘)
q.put(‘c‘)
# q.put(‘d?‘)#会卡在这里,等着队列中的数据被取走一个才存进队列
q.put(‘d?‘,False)#False ,不等待,满了就报异常,相当于put_nowait("d")
1.put的参数:
False(block = False)不等待,满了就报异常,相当于put_nowait("d")
Timeout=2,两秒后报异常
print(q.get())
print(q.get())
print(q.get())
print(q.get())#会等待队列再放
2.Get的参数:
同put
q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
1.q.get_nowait():同q.get(False)
2.q.put_nowait():同q.put(False)
3.q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
4.q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
5.q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
生产者消费者模型(见守护进程)
Manage进程之间实现数据共享
from multiprocessing import Process,Manager
import os
def work(d,l):
l.append(os.getpid())
d[os.getpid()]=os.getpid()
if __name__ == ‘__main__‘:
m=Manager()#实现进程之间数据共享
l=m.list(["egon"])
d=m.dict({"name":"dodo"})
p_l=[]
for i in range(5):
p = Process(target=work,args=(d,l))
print(p)
p.start()
p_l.append(p)
for i in p_l:
i.join()
print(d)
print(l)
print(p_l)
print(m)
输出结果:
<Process(Process-2, initial)>
<Process(Process-3, initial)>
<Process(Process-4, initial)>
<Process(Process-5, initial)>
<Process(Process-6, initial)>
{1088: 1088, 2864: 2864, 5044: 5044, 992: 992, 5708: 5708, ‘name‘: ‘dodo‘}
[‘egon‘, 5708, 1088, 2864, 5044, 992]
[<Process(Process-2, stopped)>, <Process(Process-3, stopped)>, <Process(Process-4, stopped)>, <Process(Process-5, stopped)>, <Process(Process-6, stopped)>]
<multiprocessing.managers.SyncManager object at 0x0000000001190DD8>
LOCK锁
from multiprocessing import Process,Lock
import random,time,json
def work(name,lock):
lock.acquire()#锁定了数据
with open("a.txt",‘r‘,encoding="utf-8") as f:
dic = json.loads(f.read())
if dic["count"]>0:
dic["count"]-=1
print("\\033[43m%s抢票成功\\033[0m" %name)
else:
print("\\033[46m%s抢票失败\\033[0m" % name)
with open("a.txt",‘w‘,encoding="utf-8")as f:
f.write(json.dumps(dic))
lock.release()#必须释放数据
if __name__ == ‘__main__‘:
lock = Lock()
for i in range(100):
p=Process(target=work,args=("用户%s" %i,lock))
p.start()
用进程池控制进程数:共享模块实现进程之间通讯
Pool([numprocess [,initializer [, initargs]]]):创建进程池
参数
1 numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值
2 initializer:是每个工作进程启动时要执行的可调用对象,默认为None
3 initargs:是要传给initializer的参数组
方法
p.apply同步的提交一个任务(同步:上一个任务不执行完下一步不执行),就是调用一个函数,建一个进程
p.apply_async异步
def write(conn,addr,Filename=‘a.txt‘):
while True:
try:
msg = conn.recv(1024)
if not msg:break
with open(Filename, ‘a‘, encoding="utf-8") as f:
f.write(msg.decode("utf-8")+"\\n")
logging.info("%s...写入文件%s,写入内容【%s】" % (addr, Filename, msg.decode("utf-8")))
conn.send("写入成功".encode("utf-8"))
except Exception :
break
if __name__ == ‘__main__‘:
pool = Pool(1)#写几个进程,默认是cpu核数
while True:
conn,addr = soc.accept()#接受链接
pool.apply_async(write,args=(conn,addr,))
logging.info("[%s]......链接" %conn)
以上是关于day09进程与异常处理的主要内容,如果未能解决你的问题,请参考以下文章
day9-异常处理,网络编程(基于UDP),并发编程(多进程)