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/"),
])

浙公网安备 33010602011771号