day11 线程、进程、协程、缓存
线程
基本使用:
标准线程:
例子1:创建基本线程 import threading #导入模块 def f1(arg,args): #创建函数 print(arg,args) t = threading.Thread(target=f1,args=(123,456)) #创建线程 t.start() #执行线程
自定义线程:
例子2: import threading #导入模块 class MyThread(threading.Thread): #创建一个类MyThread继承父类(threading.Thread) def __init__(self,func,args): #定义__init__构造函数 self.func = func self.args = args super(MyThread,self).__init__() #继承父类的__init__构造方法 父类的构造方法中封装了grop=None,target=None,name=None,args=(),kwargs=None,*,daeon=None def run(self): #定义run方法,此方法相当于是执行定义的方法f2。 self.func(self.args) def f2(arg): #定义一个f2方法 print(arg) obj = MyThread(f2,123) #创建一个对象obj,传参f2,123. obj.start() #执行线程
线程锁:
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。
import threading #导入线程模块 import time #导入时间模块 NUM = 10 #定义一个全局变量 def func(l): #定义一个函数 global NUM #函数内使用全局变量 l.acquire() # 上锁 NUM -= 1 #修改全局变量,让全局变量自减一 time.sleep(2) #时间等待2秒 print(NUM) l.release() # 开锁 # lock = threading.Lock() lock = threading.RLock() #加锁 for i in range(10): t = threading.Thread(target=func, args=(lock, )) #创建线程 t.start() #执行线程 # Lock只支持单层锁 # RLock支持多层锁,一般常用RLock
队列
队列的种类活类型:
1、queue.Queue先进先出队列;2、queue.LifoQueue后进先出队列;3、queue.PriorityQueue优先级队列;4、queue.deque双向队列
队列基本参数解释:
# put放数据(默认阻塞),是否阻塞,阻塞时的超时时间
# get取数据(默认阻塞),是否阻塞,阻塞时的超时时间
# queue.Queue(n),n队列最大长度
# empty() #检查队列是否为空
# qsize() #真实个数
# maxsize() #最大支持的个数
# join() #队列中的任务全部完成之后(元素没有被完成(取出))
# task_done() #结束取值任务
例子列举:
queue.Queue先进先出队列
import queue q = queue.Queue(3) # 定义队列,最多可放10个数据 q.put(11) # put存放数据 q.put(22) q.put(33,block=False, timeout=2) # 默认block阻塞,timeout超时时间 print(q.qsize()) # 真实数据个数 print(q.empty()) #查看队列是否为空 print(q.get()) q.task_done() #结束取值任务 print(q.get()) q.task_done() #结束取值任务 print(q.get(block=False, timeout=2)) # 默认block阻塞,timeout超时时间 q.task_done() #结束取值任务 print(q.empty()) #查看队列是否为空 q.join() # 阻塞进程,当队列中任务执行完毕后不再阻塞,与task_done()配合使用
queue.LifoQueue后进先出队列
q = queue.LifoQueue() q.put(123) q.put(456) q.put(789) print(q.get())
queue.PriorityQueue优先级队列
q = queue.PriorityQueue() q.put((1, "alex4")) q.put((1, "alex3")) q.put((2, "alex2")) q.put((0, "alex0")) q.put((1, "alex1")) print(q.get() print(q.get()) print(q.get()) print(q.get())
queue.deque双向队列
q = queue.deque() q.append(123) q.append(456) q.appendleft(789) print(q.pop()) print(q.popleft())
生产消费者模型———队列:
import queue import threading import time q = queue.Queue() def productor(arg): """ 买票 :param arg: :return: """ q.put(str(arg)+ '票') for i in range(300): t = threading.Thread(target=productor, args=(i, )) t.start() def consumer(arg): """ 服务器后台 :param arg: :return: """ while True: print(arg, q.get()) time.sleep(2) for j in range(3): t = threading.Thread(target=consumer, args=(j, )) t.start()
事件(event):
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False(红灯)
set:将“Flag”设置为True(绿灯)
例子:
import threading def func(i,e): print(i) e.wait() #检测是什么等,如果是红灯,停;绿灯,行 print(i+100) event = threading.Event() for i in range(10): t = threading.Thread(target=func, args=(i,event,)) t.start() event.clear() #设置成红灯 inp = input(">>>") if inp == "1": event.set() #设置成绿灯
条件(Condition)
解释:当线程满足某些条件时,才释放多个线程。
wait():
import threading def func(i,con): print(i) con.acquire() con.wait() print(i+100) con.release() c = threading.Condition() for i in range(10): t = threading.Thread(target=func, args=(i,c,)) t.start() while True: inp = input('>>>') if inp == 'q': break c.acquire() c.notify(int(inp)) c.release()
wait.for()
import threading def condition(): ret = False r = input('>>>') if r == 'true': ret = True else: ret = False return ret def func(i,con): print(i) con.acquire() con.wait_for(condition) print(i+100) con.release() c = threading.Condition() for i in range(10): t = threading.Thread(target=func, args=(i,c,)) t.start()
Time()
定时器,指N秒后执行某操作
from threading import Timer def hello(): print("hello,world") t = Timer(1,hello) #1为等待1秒,hello为函数 t.start()
线程池:
1、一个容器(最大个数)、2、取一个少一个、3、无线程时等待、4、线程执行完毕,归还线程
初级版线程池:
1 # 线程池 2 import queue 3 import threading 4 import time 5 class ThreadPool: 6 def __init__(self,maxsize=5): 7 self.maxsize = maxsize 8 self._q = queue.Queue(maxsize) 9 for i in range(maxsize): 10 self._q.put(threading.Thread) 11 12 def get_thread(self): 13 return self._q.get() 14 15 def add_thread(self): 16 self._q.put(threading.Thread) 17 18 pool = ThreadPool(5) 19 20 def task(arg,p): 21 print(arg) 22 time.sleep(1) 23 p.add_thread() 24 25 for i in range(100): 26 #thrading.Thread类 27 t = pool.get_thread() 28 obj = t(target = task,args = (i,pool,)) 29 obj.start()
高级版线程池:
1 import queue 2 import threading 3 import contextlib 4 import time 5 6 StopEvent = object() 7 8 9 class ThreadPool(object): 10 11 def __init__(self, max_num, max_task_num = None): 12 if max_task_num: 13 self.q = queue.Queue(max_task_num) 14 else: 15 self.q = queue.Queue() 16 self.max_num = max_num 17 self.cancel = False 18 self.terminal = False 19 self.generate_list = [] 20 self.free_list = [] 21 22 def run(self, func, args, callback=None): 23 """ 24 线程池执行一个任务 25 :param func: 任务函数 26 :param args: 任务函数所需参数 27 :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数) 28 :return: 如果线程池已经终止,则返回True否则None 29 """ 30 if self.cancel: 31 return 32 if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: 33 self.generate_thread() 34 w = (func, args, callback,) 35 self.q.put(w) 36 37 def generate_thread(self): 38 """ 39 创建一个线程 40 """ 41 t = threading.Thread(target=self.call) 42 t.start() 43 44 def call(self): 45 """ 46 循环去获取任务函数并执行任务函数 47 """ 48 current_thread = threading.currentThread 49 self.generate_list.append(current_thread) 50 51 event = self.q.get() 52 while event != StopEvent: 53 54 func, arguments, callback = event 55 try: 56 result = func(*arguments) 57 success = True 58 except Exception as e: 59 success = False 60 result = None 61 62 if callback is not None: 63 try: 64 callback(success, result) 65 except Exception as e: 66 pass 67 68 with self.worker_state(self.free_list, current_thread): 69 if self.terminal: 70 event = StopEvent 71 else: 72 event = self.q.get() 73 else: 74 75 self.generate_list.remove(current_thread) 76 77 def close(self): 78 """ 79 执行完所有的任务后,所有线程停止 80 """ 81 self.cancel = True 82 full_size = len(self.generate_list) 83 while full_size: 84 self.q.put(StopEvent) 85 full_size -= 1 86 87 def terminate(self): 88 """ 89 无论是否还有任务,终止线程 90 """ 91 self.terminal = True 92 93 while self.generate_list: 94 self.q.put(StopEvent) 95 96 self.q.empty() 97 98 @contextlib.contextmanager 99 def worker_state(self, state_list, worker_thread): 100 """ 101 用于记录线程中正在等待的线程数 102 """ 103 state_list.append(worker_thread) 104 try: 105 yield 106 finally: 107 state_list.remove(worker_thread) 108 109 # How to use 110 111 112 pool = ThreadPool(5) 113 114 def callback(status, result): 115 # status, execute action status 116 # result, execute action return value 117 pass 118 119 120 def action(i): 121 print(i) 122 123 for i in range(30): 124 ret = pool.run(action, (i,), callback) 125 126 time.sleep(5) 127 print(len(pool.generate_list), len(pool.free_list)) 128 print(len(pool.generate_list), len(pool.free_list)) 129 # pool.close() 130 # pool.terminate()
进程
queues(队列)数据共享
from multiprocessing import Process from multiprocessing import queues import multiprocessing def foo(i, arg): arg.put(i) print('say hi', i, arg.qsize()) if __name__ == "__main__": # li = [] li = queues.Queue(20, ctx=multiprocessing) for i in range(10): p = Process(target=foo, args=(i, li,)) # p.daemon = True p.start() # p.join()
array(数组)
from multiprocessing import Process from multiprocessing import queues import multiprocessing from multiprocessing import Array def foo(i, arg): arg[i] = i + 100 for item in arg: print(item) print('=======================') if __name__ == "__main__": li = Array('i', 10)
for i in range(10):
p.start()
Manager.dict(字典)
from multiprocessing import Process from multiprocessing import Manager def foo(i, arg): arg[i] = i + 100 print(arg.values()) if __name__ == "__main__": obj = Manager() li = obj.dict() for i in range(10): p = Process(target=foo, args=(i, li,)) p.start() p.join() # p.join() 方式二 # 方式一 import time time.sleep(1)
进程池
from multiprocessing import Pool import time def f1(arg): time.sleep(1) print(arg) if __name__ == "__main__": #windows环境下测试需要加此项 pool =Pool(5) for i in range(30): #任务,30 # pool.apply(func=f1,args=(i,)) #去进程池取任务,串行操作 pool.apply_async(func=f1,args=(i,)) #去进程池取任务,异步操作 # pool.close() #所有的任务执行完毕 # time.sleep(1) # pool.terminate() #立即终止 # pool.join() #当主进程执行到这里时,需要等待子进程全部执行完成。
进程小结:
IO密集型使用多线程,例如:爬虫
计算密集型:使用多进程
协程
原理:利用一个线程,分解一个线程,成为多个“微线程”(程序级别)。
协程是认为构造出来的,线程和进程是计算机创建的。
greenlet:底层
gevent:更高层
greentlet:
from greenlet import greenlet def test1(): print(12) gr2.switch() print(34) gr2.switch() def test2(): print(56) gr1.switch() print(78) gr1 = greenlet(test1) gr2 = greenlet(test2) gr1.switch()
gevent:
from gevent import monkey;monkey.patch_all() import gevent import requests def f(url): print("GET:%S"%url) resp = requests.get(url) data =resp.text print("%d bytes received from %s." %(len(data),url)) gevent.joinall([ gevent.spawn(f,"https://www.python.org/"), gevent.spawn(f,"https://www.yahoo.com/"), gevent.spawn(f,"https://github.com/"), ])