什么是线程:
1.线程是cpu最小的执行单位
2.进程是资源单位
3.如果将操作系统比作工厂的话,进程是车间,线程是流水线,而cpu为电源
开启一个进程默认有一个线程即主线程
多线程的好处:①当遇到IO操作时,可以将主进程分为多个线程,cpu遇到IO可能会切换到该进程的其他线程,cpu在线程间切换,
故拥有就绪态多的线程的进程被执行的概率变高,提升了进程的效率
线程的两种开启方式:①实例化Thread类②自定义MYthread类,继承Thread类,覆盖run方法
什么时候需要开启多线程,什么时候需要开启多进程:
①当我们只有1个cpu即单核:
进程对于操作系统的资源耗费非常高,而线程相反会场低(比进程低10-100倍),只有一个cpu的话,开启多线程要比多进程效率更高
②当我们有多个cpu
1.当我们的多进程都是IO时间较长时,开启多进程和多线程没有差别,因为CPU遇到IO都会切换,IO等待较长时,多进程和多线程都可以在等待时间内将其他非IO程序完成
2.当我们的多进程都cpu密集型,即运算多时,多进程要比多线程运算的快
同一个进程的多个线程是共享资源的
也就是说当我们多个线程对共有的资源修改时会导致数据的错乱,故需要线程互斥锁来保证数据安全,使用方法与进程锁一样
守护线程:
因为线程是共享数据资源的,为了保证数据安全,主线程会在所有子线程执行完毕后结束,故主线程的守护线程会在所有非守护线程执行完毕后结束
信号量:
semaphore
互斥锁是一个种特殊的信号量,即数量限制为1,
信号量同一时刻可以允许规定数量的程序同时共享数据
生产者与消费者模型问题:
消费者不知道生产者何时生产完毕,一直在取容器中的产品消费,当生产者不再生产时,消费者会一直处于阻塞状态
解决方法
①生产者在容器中放入None标记,当消费者获取到None标记时,则停止从容器中取产品
并发的起动,但生产者要优先生产完毕,并根据消费者数量放入等额的None即停止标记
from threading import Thread
import time,random
from multiprocessing import Queue
q = Queue()
def producter(name):
for i in range(5):
time.sleep(random.randint(1,2))
res = "%s的第%s个包子"%(name,i+1)
print("%s生产了第%s个包子"%(name,i+1))
q.put(res)
def customer(name):
while True:
time.sleep(random.randint(1,2))
res = q.get()
if not res :break
print("%s正在吃%s"%(name,res))
if __name__ == '__main__':
p1 = Thread(target=producter,args = ("zb",))
p2 = Thread(target=producter,args = ("xzh",))
p3 = Thread(target=producter,args = ("lqq",))
c1 = Thread(target=customer,args = ("egon",))
c2 = Thread(target=customer,args = ("alex",))
p1.start()
p2.start()
p3.start()
c1.start()
c2.start()
p1.join()
p2.join()
p3.join()
q.put(None)
q.put(None)
②使用可join的队列即JoinableQueue
同理:让生产者优先级提高,先告知q.join()总产品的数量,当消费者获取时产品,q.task_done(),给q.join()发一个通知,
当数量吻合时,q.join()执行完毕,则主线程执行完毕,将消费者设置为主线程的守护线程,则消费者同时挂掉,不会再去获取
from threading import Thread
import time,random
from multiprocessing import JoinableQueue
q = JoinableQueue()
def producter(name):
for i in range(5):
time.sleep(random.randint(1,2))
res = "%s的第%s个包子"%(name,i+1)
print("%s生产了第%s个包子"%(name,i+1))
q.put(res)
def customer(name):
while True:
time.sleep(random.randint(1,2))
res = q.get()
if not res :break
print("%s正在吃%s"%(name,res))
q.task_done()
if __name__ == '__main__':
p1 = Thread(target=producter,args = ("zb",))
p2 = Thread(target=producter,args = ("xzh",))
p3 = Thread(target=producter,args = ("lqq",))
c1 = Thread(target=customer,args = ("egon",))
c2 = Thread(target=customer,args = ("alex",))
p1.start()
p2.start()
p3.start()
c1.daemon =True
c1.start()
c2.daemon = True
c2.start()
p1.join()
p2.join()
p3.join()
q.join()