队列=管道+锁
from multiprocessing import Queue
q = Queue(5)
# 注意,这里如果我们在实例化队列这个类的时候给它传值了
# 如果我们向里面添加值得个数超过了这个数字,就会阻塞,
# 如果在向里面添加值,不会报错
# 程序就会,一直卡在这里,指导队列中有数据被取出。
q.put(1) # 向队列中添加值
q.put(1)
q.put(1)
print(q.full()) # 判断队列是否已满,满了返回True,没有满返回False
q.put(1)
q.put(1)
print(q.full())
q.get() # 向队列中取出值 注意在队列中已经没有值了。会出现阻塞状态不会报错,直到有值添加到队列中
q.get()
q.get()
print(q.empty()) # 判断队列是否为空,空了返回True,不为空返回False
q.get()
q.get()
q.get_nowait() # 取值,如果没有就会报错
"""
注意;
q.full()
q.empty()
q.get_nowait()
在多进程情况下不能使用,可能会出现偏差
列如;
在多个进程都在取数据的时候,判断了队列为空
但是在你判断过后就有进程添加了值
这个时候就会出现判断不准确
"""
进程间的通信ipc机制
from multiprocessing import Process,Queue
def func(q):
# 一个进程给队列添加对象
q.put("hello")
def index(q):
# 一个进程从对象中取值
print(q.get())
if __name__ == '__main__':
# 穿件一个队列对象
q = Queue(5)
# 创建2个进程,将队列对象传给进程
p = Process(target=func,args=(q,))
p1 = Process(target=index,args=(q,))
p.start()
p1.start()
生产者消费者模式
生产者,生产,生产数据
消费者,消费,处理数据
解决供需不平衡问题
例子;
生产者;生产包子
消费者;吃掉包子
from multiprocessing import Process,JoinableQueue
import random
import time
def producer(name,food,q):
for i in range(10):
date = "%s生产了%s,%s"%(name,food,i)
time.sleep(random.random())
print(date)
q.put(date)
def consumer(name,q):
while True:
time.sleep(random.random())
date = q.get()
print("%s吃了%s"%(name,date))
q.task_done() # 在取值的地方加上这个方法,告诉队列我已经从里面取出了一个值
if __name__ == '__main__':
q = JoinableQueue() # 创建一个队列对象
p1 = Process(target=producer,args=("老王","包子",q))
p2 = Process(target=producer,args=("老张","馒头",q))
c1 = Process(target=consumer,args=("小王",q))
c2 = Process(target=consumer,args=("小张",q))
p1.start()
p2.start()
c1.daemon=True # 将消费者的进程,设置为守护进程,主进程结束,子进程也得结束
c2.daemon=True
c1.start()
c2.start()
p1.join() # 确定当我主进程结束,生产者,必须都得执行完
p2.join()
q.join() # 判断我的这个队列是否是取完了,主进程必须得让我的这个子进程中的队列的值取完才能结束
"""
1 我们先得确定生产者必须都得生产完,才能走主进程
2 当生产者生产完了,我们还要判断消费者是否将数据处理完了
即队列中时候还有数值,用task_done()来告诉我们取值情况
这个机制我们不需要了解
3 判断我们这个队列中没有值了
我们将这两个消费者设置为守护进程
我们主进程,子进程也会走完
应为队列的特性是,如果没有值得话,,一直会处于
阻塞态
不会推出循环
"""
线程
什么是线程
注意,线程和进程都是我们虚拟化的,都是来帮我们具体的描述某种事物
线程,执行单位
进程,资源单位
举个列支来帮我们进一步了解线程
将内存比喻工厂
那进程就是工厂中的车间
而线程就是车间中的流水线
注意每一个进程都自带一个线程,线程才是执行单位,在执行中所需要的一切资源都来自于进程
所以进程是资源单位
为什么需要线程
进称,需要申请内存空间,拷贝代码,浪费资源
线程,一个进程可以开多个线程,并且线程与线程之间的数据是共享的,开线程的开销,远远比开进程小的多
线程的开启的两种方式
函数
from threading import Thread
def func():
pass
t = Thread(target=func)
t.start()
类
from threading import Thread
class func(Thread): # 创建类继承Thread
def __init__(self,name):
super().__init__()
self.name = name
def run(self): # 固定定义这个run方法,规定
print(self.name)
t = func("egon") # 直接实例化我们创建的类对象
线程的其他方法
from threading import Thread,current_thread,active_count
import os
def func():
print(current_thread().name) #查看线程号
print(os.getpid()) # 查看进程号
def index():
pass
t = Thread(target=func)
t1 = Thread(target=index)
t.daemon=True # 设置为守护进程
t1.daemon=True # 设置为守护进程
t.start()
t1.start()
print(active_count()) # 当前活跃的线程数
t.join() # 主线程等待子线程结束
t1.join() # 主线程等待子线程结束
print(os.getpid()) # 进程号是一样的
线程之间的通信
线程之间的数据是互相共用的
from threading import Thread
n = 100
def func():
global n
n = 999
t = Thread(target=func)
t.start()
print(n) # 999
# 开始n=100
# 修改后n=999
线程互斥锁
from threading import Thread, Lock
import time
n = 100
def func(mutex):
global n
mutex.acquire() # 抢锁
res = n
time.sleep(0.1)
n = res - 1
mutex.release() # 释放锁
mutex = Lock()
l_list = []
for i in range(100):
t = Thread(target=func, args=(mutex,))
t.start()
l_list.append(t)
for j in l_list:
j.join()
print(n)
date1 = time.time()