进程间通信、生产者消费者模型、线程

进程间通信、生产者消费者模型、线程,第1张

概述进程间通信 1.队列的概念 队列:先进先出 堆栈:先进后出(塞衣服) Python中用Queue()代表队列。需要导入multiprocessing模块 from multiprocessing import Queueq = Queue(5) # 括号内可以传参数 表示的是这个队列的最大存储数# 往队列中添加数据q.put(1) q.put(2)# print(q.full()) 进程间通信

1.队列的概念

队列:先进先出

堆栈:先进后出(塞衣服)

Python中用Queue()代表队列。需要导入multiprocessing模块

from multiprocessing import Queueq = Queue(5)  # 括号内可以传参数 表示的是这个队列的最大存储数# 往队列中添加数据q.put(1) q.put(2)# print(q.full())  # 判断队列是否满了q.put(3)q.put(4)q.put(5)# print(q.full())# q.put(6)  # 当队列满了之后 再放入数据 不会报错 会原地等待 直到队列中有数据被取走(阻塞态)
Queue的括号内参数:
class Queue(object):#点开源码这是一个类,不填,默认的数值非常大
full()判断队列是否满了
q.put(1)q.put(2)print(q.full())  # 判断队列是否满了,注意他的摆放顺序
put是一个一个添加值.当队列满了一个不报错,进入阻塞太进行等待
q.put(1)q.put(2)q.put(3)q.put(4)q.put(5)
取值get()、get_Nowait()

get()有个特点:等待:当队列中的数据被取完之后 再次获取 程序会阻塞 直到有人往队列中放入值

get_Nowait()顾名思义,只要没值就报错。

print(q.get())print(q.get())print(q.get())print(q.empty())  # 判断队列中的数据是否取完print(q.get())print(q.get())print(q.empty())print(q.get_Nowait())# 取值 没有值不等待直接报错
empty:判断队列中的数据是否取完 总结:

full、get_Nowait、empty都不适用多进程的情况

进程间通信IPC机制
from multiprocessing import Process,Queuedef producer(q):    q.put('hello GF~')def consumer(q):    print(q.get())if __name__ == '__main__':    q = Queue()    p = Process(target=producer,args=(q,))    c = Process(target=consumer,))    p.start()    c.start()

子进程放数据 主进程获取数据
两个子进程相互放 取数据

上述程序结果为:hello GF~
消费者生产者模型

生产者:生产/制造数据的
消费者:消费/处理数据的
例子:做包子的,买包子的
1.做包子远比买包子的多
2.做包子的远比包子的少
供需不平衡的问题

from multiprocessing import Process,Queue,JoinableQueueimport randomimport timedef producer(name,food,q):    for i in range(10):        data = '%s生产了%s%s'%(name,i)        time.sleep(random.random())        q.put(data)        print(data)def consumer(name,q):    while True:        data = q.get()        if data == None:break        print('%s吃了%s'%(name,data))        time.sleep(random.random())        q.task_done()  # 告诉队列你已经从队列中取出了一个数据 并且处理完毕了if __name__ == '__main__':    q = JoinableQueue()    p = Process(target=producer,args=('大厨egon','馒头',q))    p1 = Process(target=producer,args=('跟班tank','生蚝',q))    c = Process(target=consumer,args=('许兆龙',q))    c1 = Process(target=consumer,args=('吃货jerry',q))    p.start()    p1.start()    c.daemon = True    c1.daemon = True    c.start()    c1.start()    p.join()    p1.join()    q.join()  # 等到队列中数据全部取出

创建进程:

p = Process(target=producer,q))p.start()
线程 什么是线程?

进程线程其实都是虚拟单位,都是用来帮助我们形象的描述某种事物

进程:资源单位线程:执行单位    将内存比如成工厂    那么进程就相当于是工厂里面的车间    而你的线程就相当于是车间里面的流水线ps:每个进程都自带一个线程,线程才是真正的执行单位,进程只是在线程运行过程中提供代码运行所需要的资源
为什么要有线程?
开进程    1.申请内存空间  耗资源    2."拷贝代码"    耗资源开线程    一个进程内可以起多个线程,并且线程与线程之间数据是共享的(同一内存空间)ps:开启线程的开销要远远小于开启进程的开销
如何使用线程?

创建线程的两种方式:

方式一:

from threading import Threadimport timedef task(name):    print('%s is running'%name)    time.sleep(3)    print('%s is over'%name)开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内实例化:t = Thread(target = task,args = ('enon',))t.start()#告诉 *** 作系统开辟一个线程  线程的开销远远小于进程
打印结果有个特点:
egon is running主egon is over#egon先出来意味着创建进程的速度要比代码速度快
egon先出来意味着创建进程的速度要比代码速度快

方式二:

通过继承类,来创建。

from threading import Threadclass MyThread(Thread):    def __init__(self,name):        super().__init__()        self.name=name    def run(self):        print('%s is running' % self.name)        time.sleep(3)        print('%s is over' % self.name)t = MyThread('egon')t.start()#p.start()只是告诉计算机创建一个进程。是否先打印主线程由 *** 作系统来决定print('主')

特别提醒

只是告诉计算机创建一个进程。是否先打印主线程由 *** 作系统来决定

线程对象及其他方法

验证多个进程是不是在同一个进程下的

from threading import Thread,current_thread,active_countimport timeimport osdef task(name):    print('%s is running '%name)    print('zicurrent_thread:',current_thread().name)    print('zi',os.getpID())    time.sleep(1)    print('%s is over'%name)t = Thread(target=task,args = ('egon',))t.start()print('主')print('主current_thread:',current_thread().name)print('主',os.getpID())'''egon is running zicurrent_thread: Thread-1zi 9144主主current_thread: MainThread主 9144egon is over'''
from threading import Thread,active_countimport timeimport osdef task(name,i):    print('%s is running'%name)    time.sleep(i)    print('%s is over'%name)t = Thread(target=task,args=('egon',1))t1 = Thread(target=task,args=('jason',2))t.start()  # 告诉 *** 作系统开辟一个线程  线程的开销远远小于进程t1.start()  # 告诉 *** 作系统开辟一个线程  线程的开销远远小于进程t1.join()  # 主线程等待子线程运行完毕print('当前正在活跃的线程数',active_count())print('主')

此时的多线程join与最后面的习题一样,关键在于停的哪个线程

守护线程

先看守护进程

主进程守护一个子进程 ,主进程挂了,子进程也就挂了

p.daemon = True  # 将该进程设置为守护进程   这一句话必须放在start语句之前 否则报错p.start()time.sleep(0.3)print('皇帝jason寿正终寝')

守护线程

为什么主线程运行结束之后需要等待子线程结束才能结束呢?

主线程的结束也就意味着进程的结束,因此!主线程必须等待其他非守护线程的结束才能结束(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了,所以不能结束)

上面第二句话意味着守护进程会使得子线程结束

from threading import Thread,current_threadimport timedef task(i):    print(current_thread().name)    time.sleep(i)    print('GG')t = Thread(target=task,args=(1,))t.daemon = Truet.start()print('主')

如果没有守护进程daemon那么正常运行所有程序

线程间通信(线程之间数据互通)
from threading import Threadmoney = 666def task():    global money    money = 999t= Thread(target=task)t.start()t.join()#让线程完全走一遍再运行主线程print(money)
线程互斥锁

多个线程同时 *** 作一个数据,此时数据就是不安全的。解决方案:加锁

from threading import Thread,Lockimport timen = 100def task(mutex):    global  n    mutex.acquire()    tmp = n    time.sleep(0.1)    n = tmp - 1    mutex.release()t_List = []mutex = Lock()for i in range(100):    t = Thread(target=task,args=(mutex,))    t.start()    t_List.append(t)for t in t_List:#    t.join()#必须加这一句,等待一百个进程运行完毕之后再往下走print(n)

t.join()#必须加这一句,等待一百个进程运行完毕之后再往下走

容易迷惑的小案例
from threading import Threadfrom multiprocessing import Processimport timedef foo():    print(123)    time.sleep(1)    print("end123")def bar():    print(456)    time.sleep(3)    print("end456")if __name__ == '__main__':    t1=Thread(target=foo)    t2=Thread(target=bar)    t1.daemon=True#t1睡的时间比t2短,程序实际上走到t2,发现时间还早,因此去跑t1了    t1.start()    t2.start()    print("main-------")
t1睡的时间比t2短,程序实际上走到t2,发现时间还早,因此去跑t1了。
主线程必须等待其他非守护线程的结束才能结束如果是守护进程,那么不用等了现在所有代码都会打印出来

如果代码换成t2,那么打印结果,那么end456不会打印

总结

以上是内存溢出为你收集整理的进程间通信、生产者消费者模型、线程全部内容,希望文章能够帮你解决进程间通信、生产者消费者模型、线程所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1191954.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存