进程间通信、生产者消费者模型、线程
进程间通信1.队列的概念 队列:先进先出 堆栈:先进后出(塞衣服) Python中用Queue()代表队列。需要导入multiprocessing模块 from multiprocessing import Queue q = 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,Queue def 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~ 消费者生产者模型生产者:生产/制造数据的 from multiprocessing import Process,Queue,JoinableQueue import random import time def 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 Thread import time def 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 Thread class 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_count import time import os def 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-1 zi 9144 主 主current_thread: MainThread 主 9144 egon is over ''' from threading import Thread,active_count import time import os def 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_thread import time def task(i): print(current_thread().name) time.sleep(i) print('GG') t = Thread(target=task,args=(1,)) t.daemon = True t.start() print('主') 如果没有守护进程daemon那么正常运行所有程序 线程间通信(线程之间数据互通)from threading import Thread money = 666 def task(): global money money = 999 t= Thread(target=task) t.start() t.join()#让线程完全走一遍再运行主线程 print(money) 线程互斥锁多个线程同时操作一个数据,此时数据就是不安全的。解决方案:加锁 from threading import Thread,Lock import time n = 100 def 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 Thread from multiprocessing import Process import time def 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不会打印 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |