3,进程间通信IPC机制,线程,线程通信,互斥锁

今日内容:
1,进程间的相互通信
2,生产者消费者模型
3,线程
4,线程间通信
5,线程互斥锁
1,进程间相互通信 IPC 机制
1,基于队列来实现通信Queue,队列就相当于管道+锁
队列:先进先出
堆栈:先进后出
from multiprocessing import Queue
q = Queue(5) # 括号内可以传参数 表示的是这个队列的最大存储数
q.put(1)
q.put(2)
q.put(3)
q.put(4)
q.put(5) 向队列中添加数据
print(q.full()) 判断队列是否满了,Ture 或 False

q.get()
q.get()
print(q.empty()) 判断队列中的数据是否被取完
print(q.get()) 从队列中获取数据
print(q.get())
print(q.get())

print(q.get_nowait()) # 取值 没有值不等待,直接报错

ps:get与put要对应,数量一致,put一次只能从队列中添加一个值,get一次只能拿出一个值
如果get的数量比put的多,则队列中的值被取完了,此时不会报错,
就会等待(阻塞),等队列中有值加入时,继续取值操作,同理 put增加值时也是一样的
即q.put(6) # 当队列满了之后 再放入数据 不会报错 会原地等待 直到队列中有数据被取走(阻塞态)
当队列中的数据被取完之后 再次获取 程序会阻塞 直到有人往队列中放入值
补充:
full(), q.empty(), q.get_nowait() 都不适用于多进程的情况下

案列: from multiprocessing import Process,Queue
def scz(q): 要把队列的对象传进来*****
q.put('hello')
def xfz(q):
print(q.get())

if __name__ == '__main__':
q = Queue()
p = Process(target=scz,args=(q,))
p1 = Process(target=xfz,args=(q,))
p.start()
p1.start()
总结:两个进程之间通信,是通过队列来实现的,把 产生的数据放在队列中,让另一个进程提取
在这里要注意的是要把队列对象作为参数分别传给两个进程
2,生产者消费者模型
问题:解决供需不平衡的问题
生产者:生产或者制造数据的 做包子的
消费者:来筛选或者处理数据 买包子的
案列:(不能让阻塞在data = q.get()位置)
from multiprocessing import Process,JoinableQueue,Queue
import time
import random

def scz(name,food,q):
for i in range(0,10):
data = ('%s生产了%s包子%s'% (name,food,i))
time.sleep(0.5)
q.put(data)
print(data)


def xfz(name,q):
while True:
data = q.get()
if data == None: break # 如果data为None,说明队列中的数据已被取完
print('%s 吃掉了%s包子'% (name,data))
time.sleep(random.random())
q.task_done() # 告诉队列从队列中已取出一个数据,并且已经全部处理完毕,结束任务 *****


if __name__ == '__main__':
# q = Queue()
q = JoinableQueue() # *******
p = Process(target=scz, args=('111', '牛肉馅', q))
p1 = Process(target=scz, args=('盘龙', '白菜馅', q))
c = Process(target=xfz, args=('开门', q))
c1 = Process(target=xfz, args=('芝麻', q))
c.daemon = True
c1.daemon = True
p.start()
p1.start()

c.start()
c1.start()
#这种方法太low了
# p.join() # 确保生产者确确实实生产完了
# p1.join() # 确保生产者确确实实生产完了
# q.put(None) # 生产者生产完在队列增加一个值 None, 当取值取到None时说明队列中的数据取完了
# q.put(None) # 一个消费者用一个None,两个消费者就得用两个None ,一个消费者只要接受到none,立马结束!
# 高级方法
p.join() # 确保生产者确确实实生产完了
p1.join()

q.join() # 等到队列中的数据全部被取出 *******
3,线程

1,线程:最小的执行单位
2,进程:资源单位
将内存比作工厂,那么进程就是车间,线程就是车间里的流水线
ps:每个进程都自带一个主线程,线程是最小的执行单位,进程只是为了给线程提供资源或者代码
在进程中,每个线程都是共享进程资源
开启线程的销号要远远小于进程
进程:开辟内存空间,太耗资源
拷贝代码: 耗资源
开启线程的两种方式:
ps:开线程不需要在__main__代码块内 但是习惯性的还是写在__main__代码块内
from threading import Thread
import time

def task(name):
print('tttttu%s'% name)
time.sleep(1)
print('11111')

p = Thread(target=task,args=('teek',))
p.start() 告诉操作系统开辟一个线程 线程的开销远远小于进程
print('zhu')
第二种方式:
class MyThread(Thread):
def __init__(self,name):
super().__init__()
self.name = name

def run(self):
print("%s 是个大帅哥!"% self.name)
time.sleep(0.1)
print('但是%s疯了!'% self.name)

p = MyThread('张文诶诶')
p.start() # 启动线程
print('zhu')
线程的其他方法:
from threading import Thread,current_thread,active_count
1,current_thread 查看主线程或者子线程
print('子current_thread:',current_thread().name)
线程没有自主之分,都是平等的,在这里为了区分,才这样讲
2,active_count 查看线程是否存活
print('当前正在活跃的线程数',active_count())
3,获取子线程号
print('子',os.getpid())
守护线程:
主线程的结束也就意味着进程的结束
主线程必须等待其他非守护线程的结束才能结束
(意味子线程在运行的时候需要使用进程中的资源,而主线程一旦结束了资源也就销毁了)
案列:
from threading import Thread
import time
def task(i):
time.sleep(i)
print('tt’)

t = Thread(target=task,args=(1,))
t.daemon = True
t.start()
print('主') 主

4, 线程间通信
同一个进程的资源所有线程都可用,即数据共享
money = 666
def task():
global money
money = 999


t = Thread(target=task)
t.start()
t.join()
print(money)
5,线程互斥锁:
当多个线程或者进程想要操作同一份数据时,必须加锁,防止数据错乱!
案列:
from threading import Thread,Lock
import time
n = 100
def task(m):
global n
m.acquire()
tmp = n
time.sleep(0.1)
n = tmp -1
m.release()

tt = []
m = Lock()
for i in range(100):
t = Thread(target=task,args=(m,))
t.start()
tt.append(t)
for t in tt:
t.join()
print(n)
原文地址:https://www.cnblogs.com/Fzhiyuan/p/11342037.html