生产者消费者补充
def make_hot_dog(name,q): for i in range(5): time.sleep(random.randint(1,3)) print("%s 生产了di%s热狗"%(name,i)) q.put("%s的第%s个热狗"%(name,i)) #将生产好的数据放入共享对列中 def eat(name,q): while True: hot_dog = q.get() #将数据从共享队列中取出操作 time.sleep(random.randint(1,2)) print("%s吃了%s"%(name,hot_dog)) q.task_done() # 因为实在JoinableQueue中所以每取出一次数据后就用使用一次task_done() #要与下方.join对应起来 if __name__ == '__main__': q = JoinableQueue() #在主进程中设置一个公共的共享队列 p = Process(target=make_hot_dog,args=("藤原热狗店",q)) p.start() e = Process(target=eat,args=("阿花",q)) # e.daemon = True e.daemon = True #此处使用daemon将e进程设置为守护进程,是因为,此处消费者进程没有结束条件,当生产者结束以后 #消费者把队列中的数据取完以后,没有数据可取以后,程序又不会结束,就会卡在那里 e.start() # e.daemon = True p.join() #此处使用join是为了让主进程等待子进程结束,如果不加的话,主进程 # 主进程结束守护进程也会结束掉 print("热狗做好了") q.join() # 这里使用.join的是为了回应给主程序,消费者将队列中的数据取完了,通知之进程向下执行 print("阿花吃完了")
什么是线程
线程是操作系统最小的运算调度单位,是存在与进程中的,一个线程就是一个固定的执行流程。
真正运行程序代码的是线程,如果没有线程,进程中的资源无法被利用起来,进程中至少会有一个线程,创建进程时
产生的线程被称为主线程,当我们启动程序时操作系统就会给进程创建一个主线程,我们自己因任务需要创建的线程被称为
子线程。
from multiprocessing import Process from threading import Thread,current_thread,Lock # # def task(): print("1",current_thread()) #子线程 print("111111111") # if __name__ == "__main__": #只是在同一个进程内执行了另外一行代码,不加判断也可以 t = Thread(target=task) t.start() print("2222",current_thread()) #主线程 方法2:创建新的thread类并重新覆盖run方法 class MyThread(Thread): def run(self): print("445464654") m = MyThread() m.start()
创建线程的开销小,多个进程之间不存在子符关系,所有线程的PID都是相同的。同一个进程中的多个线程的数据是共享的。
# 同一个进程中线程间资源共享 a = 20 def task(): global a print("子线程run>>>>>") a = 100 t1 = Thread(target=task) t1.start() t1.join() #等待子进程执行结束,确保数据已被修改 print(a)
同一个进程内的线程资源共享带来的问题就是资源的抢夺,线程中也会存在安全的问题,多线程可以并发执行,一旦执行,访问同一个同一个进程中的资源就会出现数据错乱的问题。
解决数据错乱和安全的问题的方案还是互斥锁。
# 线程的安全问题 num = 10 l = Lock() def task(): global num l.acquire() a = num time.sleep(1) num = a-1 l.release() if __name__ == "__main__": for i in range(10): t = Thread(target=task) t.start() for t in enumerate()[1:]: #用于查看线程总数我们需要的是子线程,这里将主线程给通过切片拿出去 print(t) t.join() #等待所有子线程结束 print(num
要吃饭 必须具备盘子和筷子 但是一个人拿着盘子 等筷子 另一个人拿着筷子等盘子
如何避免死锁问题 :
锁不要有多个,一个足够
如果真的发生了死锁问题,必须迫使一方先交出锁
import time # 盘子 lock1 = Lock() # 筷子 lock2 = Lock() def eat1(): lock1.acquire() print("%s抢到了盘子" % current_thread().name) time.sleep(0.5) lock2.acquire() print("%s抢到了筷子" % current_thread().name) print("%s开吃了!" % current_thread().name) lock2.release() print("%s放下筷子" % current_thread().name) lock1.release() print("%s放下盘子" % current_thread().name) def eat2(): lock2.acquire() print("%s抢到了筷子" % current_thread().name) lock1.acquire() print("%s抢到了盘子" % current_thread().name) print("%s开吃了!" % current_thread().name) lock1.release() print("%s放下盘子" % current_thread().name) lock2.release() print("%s放下筷子" % current_thread().name) t1 = Thread(target=eat1) t2 = Thread(target=eat2) t1.start() t2.start()
Rlock 称之为递归锁或者可重入锁
Rlock不是用来解决死锁问题的
与Lock唯一的区别: Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次 如果一个线程已经执行过acquire 其他线程将无法执行acquire
from threading import RLock, Lock, Thread # l = Lock() # # l.acquire() # print("1") # l.acquire() # print("2") l = RLock() # l.acquire() # print("1") # l.acquire() # print("2") def task(): l.acquire() print("子run......") l.release() # 主线程锁了一次 l.acquire() l.acquire() l.release() l.release() t1 = Thread(target=task) t1.start()
可以现在被锁定的代码 同时可以被多少线程并发访问。
Lock 锁住一个马桶 同时只能有一个。
Semaphore 锁住一个公共厕所 同时可以来一堆人。
用途:仅用于控制并发访问 并不能防止并发修改造成的问题
from threading import Semaphore, Thread import time s = Semaphore(5) def task(): s.acquire() print("子run") time.sleep(3) print("子over") s.release() for i in range(10): t = Thread(target=task) t.start