首页 > 代码库 > day09进程与异常处理

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的方法:

1join()等待子进程运行结束,再向下执行

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:先启动的进程不一定先执行,要看哪个进程先建完,哪个进程先执行

2daemon守护进程

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才能通讯

进程彼此之间互相隔离,要实现进程间通信,即IPCmultiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的

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方法还有两个可选参数:blockedtimeout。如果blockedTrue(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blockedFalse,但该Queue已满,会立即抛出Queue.Full异常。

q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blockedtimeout。如果blockedTrue(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blockedFalse,有两种情况存在,如果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进程与异常处理