python16_day08【异常、多线程】
一、反射及相关
1.isinstance(obj, cls)
检查是否obj是否是类 cls 的对象
class Foo(object): pass obj = Foo() isinstance(obj, Foo)
2.issubclass(sub, super)
检查sub类是否是 super 类的派生类
class Foo(object): pass class Bar(Foo): pass issubclass(Bar, Foo)
3.反射
python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。
1 class Foo(object): 2 3 def __init__(self): 4 self.name = 'wupeiqi' 5 6 def func(self): 7 return 'func' 8 9 obj = Foo() 10 11 # #### 检查是否含有成员 #### 12 hasattr(obj, 'name') 13 hasattr(obj, 'func') 14 15 # #### 获取成员 #### 16 getattr(obj, 'name') 17 getattr(obj, 'func') 18 19 # #### 设置成员 #### 20 setattr(obj, 'age', 18) 21 setattr(obj, 'show', lambda num: num + 1) 22 23 # #### 删除成员 #### 24 delattr(obj, 'name') 25 delattr(obj, 'func')
obj.name有三种访问方式 obj.name obj.__dict__['name'] getattr(obj, 'name')
结论:反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import sys 5 6 7 def s1(): 8 print 's1' 9 10 11 def s2(): 12 print 's2' 13 14 15 this_module = sys.modules[__name__] 16 17 hasattr(this_module, 's1') 18 getattr(this_module, 's2')
1 class Foo(object): 2 3 staticField = "old boy" 4 5 def __init__(self): 6 self.name = 'wupeiqi' 7 8 def func(self): 9 return 'func' 10 11 @staticmethod 12 def bar(): 13 return 'bar' 14 15 print getattr(Foo, 'staticField') 16 print getattr(Foo, 'func') 17 print getattr(Foo, 'bar')
二、异常处理
在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!
while True: num1 = raw_input('num1:') num2 = raw_input('num2:') try: num1 = int(num1) num2 = int(num2) result = num1 + num2 except Exception, e: print '出现异常,信息如下:' print e
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
1 ArithmeticError 2 AssertionError 3 AttributeError 4 BaseException 5 BufferError 6 BytesWarning 7 DeprecationWarning 8 EnvironmentError 9 EOFError 10 Exception 11 FloatingPointError 12 FutureWarning 13 GeneratorExit 14 ImportError 15 ImportWarning 16 IndentationError 17 IndexError 18 IOError 19 KeyboardInterrupt 20 KeyError 21 LookupError 22 MemoryError 23 NameError 24 NotImplementedError 25 OSError 26 OverflowError 27 PendingDeprecationWarning 28 ReferenceError 29 RuntimeError 30 RuntimeWarning 31 StandardError 32 StopIteration 33 SyntaxError 34 SyntaxWarning 35 SystemError 36 SystemExit 37 TabError 38 TypeError 39 UnboundLocalError 40 UnicodeDecodeError 41 UnicodeEncodeError 42 UnicodeError 43 UnicodeTranslateError 44 UnicodeWarning 45 UserWarning 46 ValueError 47 Warning 48 ZeroDivisionError 49 50 更多异常
1 try: 2 raise Exception('错误了。。。') 3 except Exception,e: 4 print e
1 class WupeiqiException(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 WupeiqiException('我的异常') 11 except WupeiqiException,e: 12 print e
# assert 条件 assert 1 == 1 assert 1 == 2
三、线程
线程是最小工作单位,进程是资源池。
1.直接调用
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()
#_*_coding:utf-8_*_ import time import threading def run(n): print('[%s]------running----\n' % n) time.sleep(2) print('--done--') def main(): for i in range(5): t = threading.Thread(target=run,args=[i,]) t.start() t.join(1) print('starting thread', t.getName()) m = threading.Thread(target=main,args=[]) m.setDaemon(True) #将main线程设置为Daemon线程,它做为程序主线程的守护线程,当主线程退出时,m线程也会退出,由m启动的其它子线程会同时退出,不管是否执行完任务 m.start() m.join(timeout=2) print("---main thread done----")
- start 线程准备就绪,等待CPU调度
- setName 为线程设置名称
- getName 获取线程名称
- setDaemon 设置为后台线程或前台线程(默认)
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止 - join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
- run 线程被cpu调度后自动执行线程对象的run方法
2.线程锁(Lock、RLock)
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 import threading 4 import time 5 6 gl_num = 0 7 8 def show(arg): 9 global gl_num 10 time.sleep(1) 11 gl_num +=1 12 print(gl_num) 13 14 for i in range(10): 15 t = threading.Thread(target=show, args=(i,)) 16 t.start() 17 18 print('main thread stop')
1 #!/usr/bin/env python 2 #coding:utf-8 3 4 import threading 5 import time 6 7 gl_num = 0 8 9 lock = threading.RLock() 10 11 def Func(): 12 lock.acquire() 13 global gl_num 14 gl_num +=1 15 time.sleep(1) 16 print(gl_num) 17 lock.release() 18 19 for i in range(10): 20 t = threading.Thread(target=Func) 21 t.start() 22 print("main thread stop")
3.信号量(semaphore)
互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去
4.事件(event)
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,
那么event.wait 方法时便不再阻塞。
clear 将flag设置为False
set 将flag设置为True
1 import threading 2 3 4 def do(event): 5 print 'start' 6 event.wait() 7 print 'execute' 8 9 10 event_obj = threading.Event() 11 for i in range(10): 12 t = threading.Thread(target=do, args=(event_obj,)) 13 t.start() 14 15 event_obj.clear() 16 inp = raw_input('input:') 17 if inp == 'true': 18 event_obj.set()
5.条件(Condition)
使得线程等待,只有满足某条件时,才释放n个线程
1 import threading 2 3 def run(n): 4 con.acquire() 5 con.wait() 6 print("run the thread: %s" %n) 7 con.release() 8 9 if __name__ == '__main__': 10 11 con = threading.Condition() 12 for i in range(10): 13 t = threading.Thread(target=run, args=(i,)) 14 t.start() 15 16 while True: 17 inp = input('>>>') 18 if inp == 'q': 19 break 20 con.acquire() 21 con.notify(int(inp)) 22 con.release()
6.线程池
1 from concurrent.futures import ThreadPoolExecutor 2 import requests 3 4 5 def task(url): 6 response = requests.get(url) 7 print("得到结果:", url, len(response.content)) 8 9 url_list = [ 10 'http://www.baidu.com', 11 'http://www.sina.com.cn', 12 'http://www.autohome.com.cn' 13 ] 14 15 pool = ThreadPoolExecutor(2) 16 17 for url in url_list: 18 print("请求开始", url) 19 pool.submit(task, url)
四、进程
1 from multiprocessing import Process 2 import threading 3 import time 4 5 def foo(i): 6 print('say hi',i) 7 8 for i in range(10): 9 p = Process(target=foo, args=(i,)) 10 p.start()
注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。
1.进程数据共享
进程各自持有一份数据,默认无法共享数据
1 from multiprocessing import Process 2 3 import time 4 5 li = [] 6 7 def foo(i): 8 li.append(i) 9 print('say hi',li) 10 11 for i in range(10): 12 p = Process(target=foo, args=(i,)) 13 p.start() 14 15 print 'ending',li
1 #方法一,Array 2 from multiprocessing import Process,Array 3 4 temp = Array('i', [11,22,33,44]) 5 6 def Foo(i): 7 temp[i] = 100+i 8 for item in temp: 9 print i,'----->',item 10 11 for i in range(2): 12 p = Process(target=Foo, args=(i,)) 13 p.start() 14
1 #方法二:manage.dict()共享数据 2 from multiprocessing import Process,Manager 3 4 manage = Manager() 5 dic = manage.dict() 6 7 def Foo(i): 8 dic[i] = 100+i 9 print(dic.values()) 10 11 for i in range(2): 12 p = Process(target=Foo, args=(i,)) 13 p.start() 14 p.join()
2.进程锁
1 from multiprocessing import Process, Array, RLock 2 3 def Foo(lock, temp, i): 4 """ 5 将第0个数加100 6 """ 7 lock.acquire() 8 temp[0] = 100+i 9 for item in temp: 10 print(i,'----->',item) 11 lock.release() 12 13 lock = RLock() 14 temp = Array('i', [11, 22, 33, 44]) 15 16 for i in range(20): 17 p = Process(target=Foo, args=(lock, temp, i,)) 18 p.start()
3.进程池
1 from concurrent.futures import ProcessPoolExecutor 2 3 4 def task(arg): 5 print(arg) 6 return arg + 100 7 8 9 def call(arg): 10 data = arg.result() 11 print(data) 12 13 14 if __name__ == '__main__': 15 pool = ProcessPoolExecutor(5) 16 for i in range(10): 17 obj = pool.submit(task, i) 18 obj.add_done_callback(call)
五、协程
线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。
协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。
协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。
协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;
1.greenlet
1 from greenlet import greenlet 2 3 def test1(): 4 print(12) 5 gr2.switch() 6 print(34) 7 gr2.switch() 8 9 10 def test2(): 11 print(56) 12 gr1.switch() 13 print(78) 14 15 gr1 = greenlet(test1) 16 gr2 = greenlet(test2) 17 gr1.switch()
2.gevent
1 from gevent import monkey;monkey.patch_all() 2 import gevent 3 import requests 4 5 6 def f(url): 7 print('GET: %s' % url) 8 resp = requests.get(url) 9 print('%s bytes received from %s' % (resp.status_code, url)) 10 11 gevent.joinall([ 12 gevent.spawn(f, 'http://www.baidu.com/'), 13 gevent.spawn(f, 'http://www.sina.com.cn/'), 14 ])