my python day7

一、异常处理

  什么是异常?异常是程序运行时发生错误的信号(程序发生错误时,不处理,就会抛出异常)

  错误分为 1.语法错误2.逻辑错误

  异常包括三部分:异常追踪信息、异常类、异常值。

  异常处理方法:

  1.如果错误发生的条件是可预知的,我们需要用if来处理,在错误发生之前来预防.

1 age = 10
2 while True:
3     a = input("<<<").strip()
4     if a.isdigit():
5         a = int(a)
6         if a== age:
7             print("you got it ")
8             break
View Code

2.如果错误发生的条件是不可预知的,用try...expect,在错误发生之后进行处理.

1 t = (i for i in range(5))
2 while True:
3     try:
4         print(t.__next__())
5     except StopIteration:
6         print("finish")
7         break
View Code
 1 t = (i for i in range(5))
 2 while True:
 3     try:
 4         print(t.__next__())
 5     except StopIteration:
 6         print("finish")
 7         break
 8     else:
 9         print("没有异常")   #当try执行时,else就会执行
10     finally:
11         print("无论异常与否,都会打印")
View Code

二、网络编程

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

也有人将socket说成ip+port,ip是用来标识互联网中的一台主机的位置,而port是用来标识这台机器上的一个应用程序,ip地址是配置到网卡上的,而port是应用程序开启的,ip与port的绑定就标识了互联网中独一无二的一个应用程序,而程序的pid是同一台机器上不同进程或者线程的标识.
套接字ipc:一台主机上多个应用程序之间的通讯。套接字有两种,一种基于文件类型套接字:家族名:AF_UNIX 另一种基于网络类型套接字:家族名:AF_INET

客户端与服务端的交互过程:从服务端说起:创建一个socket对象,然后与端口进行绑定bind,对端口进行监听listen,调用accept阻塞直到客户端进行连接,客户端初始化一个socket对象,调用connect与服务端进行连接,向服务端发送请求,客户端接受并处理请求,然后把回应数据,客户端获得数据,最后关闭连接,一次交互就结束。
 1 #实例化socket对象
 2 import socket
 3 socket.socket(socket_family,socket_type,protocal=0)
 4 socket_family :套接字家族,AF_UNIX(基于文件)AF_INET(基于网络)
 5 socket_type:SOCK_STREAM(流),SOCK_DGRAM
 6 
 7 获取tcp/ip套接字
 8 tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 9 获取udp/ip套接字
10 udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
11 from socket import *
12 tcp_socket = socket(AF_UNIX,SOCK_STREAM)
13 udp_socket = socket(AF_INET,SOCK_DGRAM)
View Code
s= socket(socket.AF_INET,socket.SOCK_STREAM)
服务端套接字函数
s.blid() 绑定(主机,端口号)到套接字
s.listen() 开始tcp监听
s.accept() 阻塞,直到客户端进行连接
客户端套接字函数
s.connect() tcp服务端连接
#公共用途套接字函数
s.recv()接受tcp数据
s.send()发送tcp数据
s.recvfrom()接受udp数据
s.sendto()发送udp数据
s.close()关闭套接字
 1 #tcp客户端
 2 import socket
 3 tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
 4 tcp_server.bind(("127.0.0.1",8000))
 5 tcp_server.listen(5)
 6 conn,addr = tcp_server.accept()
 7 print(conn,addr)
 8 data = conn.recv(1024)
 9 print("接受客户端的信息",data.decode("utf-8")) #接受信息
10 conn.send(data.upper())
11 conn.close()
12 tcp_server.close()
13 # tcp服务端
14 import socket
15 tcp_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
16 tcp_client.connect(("127.0.0.1",8000))
17 tcp_client.send(b"hello")  #发送信息
18 data2 = tcp_client.recv(1024)
19 print("接受服务端的信息:",data2.decode("utf-8"))
20 tcp_client.close()
View Code
 1 #udp服务端
 2 import socket
 3 udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
 4 udp_server.bind(("127.0.0.1",8000))
 5 msg,addr = udp_server.recvfrom(2014)
 6 print("接受客户端的信息",msg.decode("utf-8"))
 7 udp_server.sendto(msg.upper(),addr)
 8 import socket                                                      
 9 udp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)       
10 udp_client.sendto(b"hello",("127.0.0.1",8000))                     
11 msg,addr = udp_client.recvfrom(1024)                               
12 print("接受服务端的信息",msg.decode("utf-8"))                              
View Code

基于tcp的套接字

tcp是基于链接的,必须先启动服务端,然后再启动客户端去链接

 1 #tcp服务端
 2 1 ss = socket() #创建服务器套接字
 3 2 ss.bind()      #把地址绑定到套接字
 4 3 ss.listen()      #监听链接
 5 4 inf_loop:      #服务器无限循环
 6 5     cs = ss.accept() #接受客户端链接
 7 6     comm_loop:         #通讯循环
 8 7         cs.recv()/cs.send() #对话(接收与发送)
 9 8     cs.close()    #关闭客户端套接字
10 9 ss.close()        #关闭服务器套接字(可选)
1 #tcp客户端
2 1 cs = socket()    # 创建客户套接字
3 2 cs.connect()    # 尝试连接服务器
4 3 comm_loop:        # 通讯循环
5 4     cs.send()/cs.recv()    # 对话(发送/接收)
6 5 cs.close()            # 关闭客户套接字

udp是无链接的,先启哪一端都可以

1 #udp服务端
2 1 ss = socket()   #创建一个服务器的套接字
3 2 ss.bind()       #绑定服务器套接字
4 3 inf_loop:       #服务器无限循环
5 4     cs = ss.recvfrom()/ss.sendto() # 对话(接收与发送)
6 5 ss.close()                         # 关闭服务器套接字
1 cs = socket()   # 创建客户套接字
2 comm_loop:      # 通讯循环
3     cs.sendto()/cs.recvfrom()   # 对话(发送/接收)
4 cs.close()                      # 关闭客户套接字

1 #加入一条socket配置,重用ip和端口
2 
3 phone=socket(AF_INET,SOCK_STREAM)
4 phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
5 phone.bind(('127.0.0.1',8080))

三、进程

操作系统:一个用来协调、管理计算机硬件和软件资源的系统程序

多道程序设计:提高cpu利用率

进程:一个程序在一个数据集上的一次动态执行过程,负责执行任务的是cpu。

 进程包含三部分:程序、数据集、进程控制块。

进程是最小的资源单位

并发:是指系统具有处理多个任务的能力,而一个cpu在同一时刻只能处理一个任务,单个cpu+多道程序设计实现并发

并行:是指系统在同一时刻具有处理多个任务的能力,只有具备多个cpu才能实现

同步:一个进程执行任务的时候,一直等到任务完成,而进程一直处于激活状态

异步:一个进程执行一个任务的时候,不会等到任务完成才执行,当任务完成后,再回来处理。

阻塞调用是指调用结果返回之前,当前线程会被挂起(如遇到io操作)。函数只有在得到结果之后才会将阻塞的线程激活

多进程:由于GIL存在,python中的多线程并不是真正的多线程,如果要充分使用cpu资源,大部分使用的是多进程.

multiprocessing模块

多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

Process类

创建的是子进程
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动) 强调: 1. 需要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
参数介绍
1 group参数未使用,值始终为None 2 3 target表示调用对象,即子进程要执行的任务 4 5 args表示调用对象的位置参数元组,args=(1,2,'egon',) 6 7 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18} 8 9 name为子进程的名称
方法介绍:
p.start() ,启动进程,调用子进程中run方法
p.run()进程启动调用的方法,自定义类中必须实现该方法
p.terminate()强制终止进程
p.is_alive() 判断进程是否执行
p.join() 主进程等待p终止,主进程等待,子进程处于运行状态,或达到运行timeout。
属性介绍:
p.daemon:
默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置.
p.name:进程的名字
p.pid:进程号
p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)

p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)
注意:在windows中Process()必须放到# if __name__ == '__main__':下
创建并开启子进程的两种方式:
 1 import time                                                   
 2 import random                                                 
 3 from multiprocessing import Process                           
 4 def print_name(name):                                         
 5     time.sleep(random.randint(1,3))                           
 6     print("my name is %s"%name)                               
 7                                                               
 8 p1 = Process(target=print_name,args=("Ezhizen",))  #必须加,      
 9 p2 = Process(target=print_name,kwargs={"name":"Ryoma"})       
10                                                               
11 p1.start()    #启动进程p1                                         
12 p2.start()    #启动进程p2                                         
13 p1.join()    #等待p1运行完成                                        
14 p2.join()     #等待p2运行完成                                       
15 print("welcome")                                              
16                                                               
View Code
 1 import multiprocessing                                 
 2 class MyProcess(multiprocessing.Process):  #继承Process类 
 3     def __init__(self,name):                           
 4         super(MyProcess,self).__init__()               
 5         self.name = name                               
 6     def run(self):                                     
 7         time.sleep(random.randint(1,3))                
 8         print("my name is %s"%self.name)               
 9                                                        
10                                                        
11                                                        
12 p1= MyProcess("Ezhizen")                               
13 p2 = MyProcess("Ryoma")                                
14 p1.start()                                             
15 p2.start()                                             
16 p1.join()                                              
17 p2.join()                                              
18 print(" Echizen Ryoma")                                
View Code
 1 from multiprocessing import Process
 2 from threading import Thread
 3 import time
 4 def foo():
 5     print(123)
 6     time.sleep(1)
 7     print("end123")
 8 
 9 def bar():
10     print(456)
11     time.sleep(3)
12     print("end456")
13 
14 
15 p1=Process(target=foo)
16 p2=Process(target=bar)
17 
18 p1.daemon=True
19 p1.start()
20 p2.start()
21 # time.sleep(1)
22 print("main-------")#打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止
View Code

进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,

而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理.

#加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
虽然可以用文件共享数据实现进程间通信,但问题是:
1.效率低(共享数据基于文件,而文件是硬盘上的数据)
2.需要自己加锁处理
 1 #由并发变成了串行,牺牲了运行效率,但避免了竞争
 2 from multiprocessing import Process,Lock
 3 import os,time
 4 def work(lock):
 5     lock.acquire()
 6     print('%s is running' %os.getpid())
 7     time.sleep(2)
 8     print('%s is done' %os.getpid())
 9     lock.release()
10 if __name__ == '__main__':
11     lock=Lock()
12     for i in range(3):
13         p=Process(target=work,args=(lock,))
14         p.start()
View Code

为了解决这个问题,采用队列和管道的方法。

Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。 
maxsize 是队列中最大允许项数
1 q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
2 q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
3  
4 q.get_nowait():同q.get(False)
5 q.put_nowait():同q.put(False)
6 
7 q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
8 q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
9 q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
 1 import time,random,os
 2 def consumer(q):
 3     while True:
 4         res=q.get()
 5         time.sleep(random.randint(1,3))
 6         print('33[45m%s 吃 %s33[0m' %(os.getpid(),res))
 7 
 8         q.task_done() #向q.join()发送一次信号,证明一个数据已经被取走了
 9 
10 def producer(name,q):
11     for i in range(10):
12         time.sleep(random.randint(1,3))
13         res='%s%s' %(name,i)
14         q.put(res)
15         print('33[44m%s 生产了 %s33[0m' %(os.getpid(),res))
16     q.join()
17 
18 
19 if __name__ == '__main__':
20     q=JoinableQueue()
21     #生产者们:即厨师们
22     p1=Process(target=producer,args=('包子',q))
23     p2=Process(target=producer,args=('骨头',q))
24     p3 = Process(target=producer, args=('泔水', q))
25 
26     # 消费者们:即吃货们
27     c1 = Process(target=consumer, args=(q,))
28     c2 = Process(target=consumer, args=(q,))
29     c1.daemon = True
30     c2.daemon = True
31 
32     # 开始
33     p_l = [p1, p2, p3, c1, c2]
34     for p in p_l:
35         p.start()
36 
37     p1.join()
38     p2.join()
39     p3.join()
40     print('')
View Code
四、线程
线程 为了降低上下文切换的消耗,提高系统的并发性,突破一个进程只能做一件事的缺陷,线程是最小的执行单元。
1.一个程序至少有一个进程,一个进程至少有一个线程。
2.进程在执行过程中拥有独立的内存单元,而多个线程共享共存的,从而提高程序的运行效率。
3.每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口。线程不能独立执行,必须依存在应用程序上。
4.进程是具有一定独立功能的程序,关于数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单元。
5.一个线程可以创建和撤销另一个线程。
6.线程是进城的实体,是cpu调整和分配的基本单位。
7.同一个进程中多个线程可以并发执行。
启动线程的两种方法
1 import threading
2 import time
3 def print_name(name):
4     time.sleep(3)
5     print("my name is %s"%name)
6 
7 t = threading.Thread(target=print_name,args=("Ezhizen",))
8 t.start()
9 print("dddddd")
View Code

 1 import threading,time
 2 class Mythread(threading.Thread):
 3     def __init__(self,name):
 4         super(Mythread,self).__init__()
 5         self.name = name
 6     def run(self):
 7         time.sleep(3)
 8         print("my name is %s"%self.name)
 9 t = Mythread("Ezhizen")
10 t.start()
11 print("jjjj")
View Code
 1 from  threading import Thread
 2 from multiprocessing import Process
 3 import os
 4 def work():
 5     global n
 6     n=0
 7 
 8 
 9 n=100
10 p=Process(target=work)
11 p.start()
12 p.join()
13 print('主进程',n) #毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100
14 
15 
16 n=1
17 t=Thread(target=work)
18 t.start()
19 t.join()
20 print('主线程',n) #查看结果为0,因为同一进程内的线程之间共享进程内的数据
View Code

Thread实例对象的方法
  # isAlive(): 返回线程是否活动的。
  # getName(): 返回线程名。
  # setName(): 设置线程名。

threading模块提供的一些方法:
  # threading.currentThread(): 返回当前的主线程变量。
  # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

#1.对主进程来说,运行完毕指的是主进程代码运行完毕 #2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕

#1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,

#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。

 1 from threading import Thread
 2 import time
 3 def foo():
 4     print(123)
 5     time.sleep(1)
 6     print("end123")
 7 
 8 def bar():
 9     print(456)
10     time.sleep(3)
11     print("end456")
12 
13 
14 t1=Thread(target=foo)
15 t2=Thread(target=bar)
16 
17 t1.daemon=True
18 t1.start()
19 t2.start()
20 print("main-------")
View Code

锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据


 1 from threading import current_thread,Thread,Lock
 2 import os,time
 3 def task():
 4     global n
 5     print('%s is running' %current_thread().getName())
 6     temp=n
 7     time.sleep(0.5)
 8     n=temp-1
 9 
10 
11 if __name__ == '__main__':
12     n=100
13     lock=Lock()
14     threads=[]
15     start_time=time.time()
16     for i in range(100):
17         t=Thread(target=task)
18         threads.append(t)
19         t.start()
20     for t in threads:
21         t.join()
22 
23     stop_time=time.time()
24     print('主:%s n:%s' %(stop_time-start_time,n))
View Code

线程中的队列

 1 import queue
 2 q = queue.Queue()   #先进先出
 3 q.put(1)
 4 q.put(2)
 5 q.put(3)
 6 print(q.get())
 7 print(q.get())
 8 print(q.get())
 9 q2 = queue.LifoQueue()  #后进先出
10 q2.put(1)
11 q2.put(2)
12 q2.put(3)
13 print(q2.get())
14 print(q2.get())
15 print(q2.get())
16 q3 = queue.PriorityQueue()  #设置优先级
17 q3.put((3,"a"))
18 q3.put((2,"b"))
19 q3.put((1,"c"))
20 print(q3.get())
21 print(q3.get())
22 print(q3.get())
View Code

五、协程

协程:是单线程下的并发,又称微线程,纤程


  1. 必须在只有一个单线程里实现并发
  2. 修改共享数据不需加锁
  3. 用户程序里自己保存多个控制流的上下文栈
  4. 附加:一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))

greenlet运用
 1 from greenlet import greenlet
 2 
 3 def eat(name):
 4     print('%s eat 1' %name)
 5     g2.switch('egon')
 6     print('%s eat 2' %name)
 7     g2.switch()
 8 def play(name):
 9     print('%s play 1' %name)
10     g1.switch()
11     print('%s play 2' %name)
12 
13 g1=greenlet(eat)
14 g2=greenlet(play)
15 
16 g1.switch('egon')#可以在第一次switch时传入参数,以后都不需要
View Code

gevent的运用

g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的

g2=gevent.spawn(func2)

g1.join() #等待g1结束

g2.join() #等待g2结束

#或者上述两步合作一步:gevent.joinall([g1,g2])

g1.value#拿到func1的返回值
遇到IO阻塞时会自动切换任务
 1 from gevent import monkey;monkey.patch_all()
 2 import gevent
 3 import requests
 4 import time
 5 
 6 def get_page(url):
 7     print('GET: %s' %url)
 8     response=requests.get(url)
 9     if response.status_code == 200:
10         print('%d bytes received from %s' %(len(response.text),url))
11 
12 
13 start_time=time.time()
14 gevent.joinall([
15     gevent.spawn(get_page,'https://www.python.org/'),
16     gevent.spawn(get_page,'https://www.yahoo.com/'),
17     gevent.spawn(get_page,'https://github.com/'),
18 ])
19 stop_time=time.time()
20 print('run time is %s' %(stop_time-start_time))
View Code




 
 
 
 
原文地址:https://www.cnblogs.com/Ezhizen/p/11234582.html