Python学习第八天

SocketServer模块:

SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器端创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求。

为了好理解,我们先看个例子吧:

 1 import socketserver
 2 class MyTCPHandler(socketserver.BaseRequestHandler):
 3     def handle(self):
 4         while True:
 5             print("New Conn:",self.client_address)
 6             data=self.request.recv(1024)
 7             if not data:break
 8             print("Client Says:",data.decode())
 9             self.request.send(data)
10 if __name__=='__main__':
11     HOST,PORT="localhost",50007
12     server=socketserver.ThreadingTCPServer((HOST,PORT),MyTCPHandler)
13     server.serve_forever()
服务器端
 1 import socket
 2 ip_port=('127.0.0.1',50007)
 3 sk=socket.socket()
 4 sk.connect(ip_port)
 5 while True:
 6     msg=input(">>:").strip()
 7     sk.sendall(bytes(msg,'utf-8'))
 8     server_reply=sk.recv(1024)
 9     print("Server Reply:",str(server_reply,'utf-8'))
10 sk.close()
客户端

上面例子的效果是 客户端输入什么内容,然后服务器端就会回应什么内容。

 异常处理:

(先看以下内容:)

一、isinstance(obj, cls)

 检查是否obj是否是类 cls 的对象

1 class Foo(object):
2     pass
3  
4 obj = Foo()
5  
6 isinstance(obj, Foo)

二、issubclass(sub, super)

检查sub类是否是 super 类的派生类

1 class Foo(object):
2     pass
3  
4 class Bar(Foo):
5     pass
6  
7 issubclass(Bar, Foo)

1、异常基础

在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是显示一个提示的页面。

1 try:
2     pass
3 except Exception as ex:
4     pass

 需求:将用户输入的两个数字相加

 1 while True:
 2     num1=input('num1')
 3     num2=input('num2')
 4     a=range(10)
 5     try:
 6         num1=int(num1)
 7         num2=int(num2)
 8         result=num1+num2
 9         a[11]
10     except ValueError as e:
11         print("Value err:",e)
12     except IndexError as e:
13         print("Index err:",e)
14     except BaseException as e:
15         print("出现异常,信息如下:",e)
16         print(e)
View Code

2、异常种类

python中的异常种类非常多,每个异常专门用于处理某一项异常!!!

1 dic = ["tutu", 'peony']
2 try:
3     dic[10]
4 except IndexError, e:
5     print e
异常实例IndexError
1 dic = {'k1':'v1'}
2 try:
3     dic['k20']
4 except KeyError, e:
5     print e
异常实例: KeyError
1 s1 = 'hello'
2 try:
3     int(s1)
4 except ValueError, e:
5     print e
异常实例:ValueError

异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。

# 未捕获到异常,程序直接报错
 
s1 = 'hello'
try:
    int(s1)
except IndexError as e:
    print (e)

所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:

1 s1 = 'hello'
2 try:
3     int(s1)
4 except IndexError as e:
5     print (e)
6 except KeyError as e:
7     print (e)
8 except ValueError as e:
9     print (e)

万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:

1 s1 = 'hello'
2 try:
3     int(s1)
4 except Exception as e:
5     print (e)

虽然有这个万能异常,其他异常也是不可以忽略的!对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。

1 s1 = 'hello'
2 try:
3     int(s1)
4 except KeyError as e:
5     print ('键错误')
6 except IndexError as e:
7     print ('索引错误')
8 except Exception as e:
9     print ('错误')

3、异常其他结构

try:
    # 主代码块
    pass
except KeyError as e:
    # 异常时,执行该块
    pass
else:
    # 主代码块执行完,执行该块
    pass
finally:
    # 无论异常与否,最终执行该块
    pass

4、主动触发异常

try:
    raise Exception('错误了。。。')
except Exception as e:
    print (e)

5、自定义异常

 1 class MyException(Exception):
 2  
 3     def __init__(self, msg):
 4         self.message = msg
 5  
 6     def __str__(self):
 7         return self.message
 8  
 9 try:
10     raise MyException('我的异常')
11 except MyException as e:
12     print (e)

6、断言

# assert 条件
 
assert 1 == 1
 
assert 1 == 2

 

 1 class AlexException(Exception):
 2     def __init__(self,msg):
 3         self.message==msg
 4     def __str__(self):
 5         return self.message
 6 a=1
 7 try:
 8     assert a==1
 9 except AlexException as e:
10     print(e)
11 else:
12     print("hahahh  else")
13 finally:
14     print("no matter right or wrong run this anyway!")
自定义异常和断言实例

 线程与进程:

线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

线程有2种调用方式,如下:

 1 import threading
 2 import time
 3  
 4 def sayhi(num): #定义每个线程要运行的函数
 5  
 6     print("running on number:%s" %num)
 7  
 8     time.sleep(3)
 9  
10 if __name__ == '__main__':
11  
12     t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
13     t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
14  
15     t1.start() #启动线程
16     t2.start() #启动另一个线程
17  
18     print(t1.getName()) #获取线程名
19     print(t2.getName())
直接调用
 1 import threading
 2 import time
 3  
 4  
 5 class MyThread(threading.Thread):
 6     def __init__(self,num):
 7         threading.Thread.__init__(self)
 8         self.num = num
 9  
10     def run(self):#定义每个线程要运行的函数
11  
12         print("running on number:%s" %self.num)
13  
14         time.sleep(3)
15  
16 if __name__ == '__main__':
17  
18     t1 = MyThread(1)
19     t2 = MyThread(2)
20     t1.start()
21     t2.start()
继承式调用

更多方法:

    • start            线程准备就绪,等待CPU调度
    • setName      为线程设置名称
    • getName      获取线程名称
    • setDaemon   设置为后台线程或前台线程(默认)
                         如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                          如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
    • join              逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
    • run              线程被cpu调度后执行Thread类对象的run方法

请看下面的实例:

 1 import time
 2 import threading
 3  
 4 def run(n):
 5  
 6     print('[%s]------running----\n' % n)
 7     time.sleep(2)
 8     print('--done--')
 9  
10 def main():
11     for i in range(5):
12         t = threading.Thread(target=run,args=[i,])
13         #time.sleep(1)
14         t.start()
15         t.join(1)
16         print('starting thread', t.getName())
17  
18  
19 m = threading.Thread(target=main,args=[])
20 m.setDaemon(True) #将主线程设置为Daemon线程,它退出时,其它子线程会同时退出,不管是否执行完任务
21 m.start()
22 #m.join(timeout=2)
23 print("---main thread done----")

线程锁

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。所以,可能出现如下问题:

 1 import threading
 2 import time
 3 
 4 gl_num = 0
 5 
 6 def show(arg):
 7     global gl_num
 8     time.sleep(1)
 9     gl_num +=1
10     print (gl_num)
11 
12 for i in range(10):
13     t = threading.Thread(target=show, args=(i,))
14     t.start()
15 
16 print ('main thread stop')
未使用锁
 1 import threading
 2 import time
 3 
 4 gl_num = 0
 5 
 6 lock = threading.RLock()
 7 
 8 def Func():
 9     lock.acquire()
10     global gl_num
11     gl_num +=1
12     time.sleep(1)
13     print(gl_num)
14     lock.release()
15 
16 for i in range(10):
17     t = threading.Thread(target=Func)
18     t.start()
19 print ('main thread stop')
使用锁

 RLock(递归锁)

说白了就是在一个大锁中还要再包含子锁 它的用处是避免两个线程在执行的时候被其他的插在中间执行了,而我们要的结果是它俩一起完成执行不被打扰。

 1 import threading,time
 2  
 3 def run1():
 4     print("grab the first part data")
 5     lock.acquire()
 6     global num
 7     num +=1
 8     lock.release()
 9     return num
10 def run2():
11     print("grab the second part data")
12     lock.acquire()
13     global  num2
14     num2+=1
15     lock.release()
16     return num2
17 def run3():
18     lock.acquire()
19     res = run1()
20     print('--------between run1 and run2-----')
21     res2 = run2()
22     lock.release()
23     print(res,res2)
24  
25  
26 if __name__ == '__main__':
27  
28     num,num2 = 0,0
29     lock = threading.RLock()
30     for i in range(10):
31         t = threading.Thread(target=run3)
32         t.start()
33  
34 while threading.active_count() != 1:
35     print(threading.active_count())
36 else:
37     print('----all threads done---')
38     print(num,num2)
View Code

Semaphore(信号量)

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 。

 1 import threading,time
 2  
 3 def run(n):
 4     semaphore.acquire()
 5     time.sleep(1)
 6     print("run the thread: %s\n" %n)
 7     semaphore.release()
 8  
 9 if __name__ == '__main__':
10  
11     num= 0
12     semaphore  = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
13     for i in range(20):
14         t = threading.Thread(target=run,args=(i,))
15         t.start()
16  
17 while threading.active_count() != 1:
18     pass #print threading.active_count()
19 else:
20     print('----all threads done---')
21     print(num)
View Code

线程间同步和交互:

通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

 1 import threading
 2 import random
 3 import time
 4 def light():
 5     if not event.isSet():
 6         event.set()#wait就不阻塞#绿灯状态
 7     count=0
 8     while True:
 9         if count<10:
10             print('\033[42;1m--green light on---\033[0m')
11         elif count<13:
12             print('\033[43;1m--yellow light on---\033[0m')
13         elif count<20:
14             if event.isSet():
15                 event.clear()
16             print('\033[41;1m--green light on---\033[0m')
17         else:
18             count=0
19             event.set()
20         time.sleep(1)
21         count+=1
22 def car(n):
23     while 1:
24         time.sleep(1)
25         if event.isSet():#绿灯
26             print("car[%s] is running..."%n)
27         else:
28             print("car [%s] is waiting for the red light..."%n)
29             event.wait()
30 if __name__=='__main__':
31     event=threading.Event()
32     Light=threading.Thread(target=light)
33     Light.start()
34     for i in range(3):
35         t=threading.Thread(target=car,args=(i,))
36         t.start()
红绿灯

多进程: 

 1 from multiprocessing import Process
 2 import time
 3 def f(name):
 4     time.sleep(2)
 5     print('hello', name)
 6 
 7 if __name__ == '__main__':
 8     p = Process(target=f, args=('bob',))
 9     p2 = Process(target=f, args=('bob',))
10     p.start()
11     p2.start()#该句和上面同步执行
12     p.join()

注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。

下面是一个扩展的例子,可以显示每个进程所涉及的ID:

 1 from multiprocessing import Process
 2 import os
 3 
 4 def info(title):
 5     print(title)
 6     print('module name:', __name__)
 7     print('parent process:', os.getppid())
 8     print('process id:', os.getpid())
 9     print("\n\n")
10 
11 def f(name):
12     info('\033[31;1mfunction f\033[0m')
13     print('hello', name)
14 
15 if __name__ == '__main__':
16     info('\033[32;1mmain process line\033[0m')
17     p = Process(target=f, args=('bob',))
18     p.start()
19     p.join()
View Code

进程间通讯  

不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:

Queues

使用方法跟threading里的queue差不多

 1 from multiprocessing import Process,Queue
 2 def f(q):
 3     q.put([42,None,'hello'])
 4 if __name__=='__main__':
 5     que=Queue()
 6     p=Process(target=f,args=(que,))
 7     p2=Process(target=f,args=(que,))
 8     p.start()
 9     p2.start()
10     print('from parent:',que.get())
11     print('from parent2:',que.get())
12     p.join()

Pipes

 1 from multiprocessing import Process, Pipe
 2  
 3 def f(conn):
 4     conn.send([42, None, 'hello'])
 5     conn.close()
 6  
 7 if __name__ == '__main__':
 8     parent_conn, child_conn = Pipe()
 9     p = Process(target=f, args=(child_conn,))
10     p.start()
11     print(parent_conn.recv())   # prints "[42, None, 'hello']"
12     p.join()

Managers

 1 from multiprocessing import Process, Manager
 2 
 3 def f(d, l):
 4     d[1] = '1'
 5     d['2'] = 2
 6     d[0.25] = None
 7     l.append(1)
 8     print(l)
 9 
10 if __name__ == '__main__':
11     with Manager() as manager:
12         d =manager.dict()
13 
14         l = manager.list(range(5))
15         p_list = []
16         for i in range(10):
17             p = Process(target=f, args=(d, l))
18             p.start()
19             p_list.append(p)
20         for res in p_list:
21             res.join()
22 
23         print(d)
24         print(l)
View Code

进程同步:

 1 from multiprocessing import Process, Lock
 2 
 3 def f(l, i):
 4     l.acquire()
 5     try:
 6         print('hello world', i)
 7     finally:
 8         l.release()
 9 
10 if __name__ == '__main__':
11     lock = Lock()
12 
13     for num in range(10):
14         Process(target=f, args=(lock, num)).start()
View Code

进程池  

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

 1 from  multiprocessing import Process,Pool
 2 import time
 3  
 4 def Foo(i):
 5     time.sleep(2)
 6     return i+100
 7  
 8 def Bar(arg):
 9     print('-->exec done:',arg)
10  
11 pool = Pool(5)
12  
13 for i in range(10):
14     pool.apply_async(func=Foo, args=(i,),callback=Bar)
15     #pool.apply(func=Foo, args=(i,))
16  
17 print('end')
18 pool.close()
19 pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

 

posted @ 2016-03-15 20:33  Peony_Y  阅读(160)  评论(0编辑  收藏  举报