进程通信--Queue(队列)进程之间有时需要共享一些信息,这就用到了Queue
q = multiprocessing.Queue(3) # 3 表示只能存放 3 个数据
q表示队列对象
参数:maxsize是队列允许的最大项数。如果省略,则无大小限制。
Queue–队列(先进先出)
put(),向队列中存放数据。如果队列已满,此方法将阻塞程序运行
get(),返回q中的项目,如果q为空,将阻塞程序,直到列表中有项目可用
get_nowait(): 强取,不等待,直接抛出异常
full()如果 q 已满,返回为 True
q.empty() 如果调用此方法时 q 为空,返回 True。
q.qsize()#返回一个数值,表示当前队列的消息数量
线程
操作系统 为每一个进程分配独立的内存空间,
进程缺点:占用独立的资源,所以对系统开销比较大。
一般情况下,我们可以使用多线程来完成多任务的开发。
一个进程中,包含了多个线程,线程对系统开销要小的多。
一个进程当中至少有一个线程,默认这个线程我们叫他为,主线程。
多线程 VS 多进程
#相同:线程与进程都可以完成多任务开发
#不同:1,进程是系统进行资源分配和调度的一个独立单位;
#2,线程是进行的一个实体,是CPU调度和分派的基本单位,线程
#是比进程更小的能够独立运行的基本单位。
#3,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源
#(比如:程序的计数器,一组寄存器和栈),他是可以与同一进程当中的
#其他线程共享进程所拥有的全部资源。
#小结:1,一个程序至少有一个进程,一个进程至少有一个线程
#2,线程是划分尺度较小的进程(资源比进程占用的少),使得多线程程序的并发性高。
#3,进程在执行过程中拥有独立的内存单元,而多个线程共享这块内存空间,从而极大地提高了程序的运行效率。
#4,线程不能独立执行,必须依存在进程中。
#多线程开发
#1,引入模块 import threading
#2,创建线程
#(1)方法一:t=threading.Thread(target=函数名,args=(参数1,参数2.。。)) 启动线程 t.start()
#(2)方法二:创建一个自己的线程类,继承Thread类,重写run方法。
#3,查看多线程的数量
#threading.enumerate()
#说明:Return a list of all Thread objects currently alive.(返回当前活的一个线程对象列表)
#4,线程的执行顺序
#多线程的执行顺序是不确定的。
#5,线程的状态
#当线程执行到 sleep语句,线程将进入到阻塞(blocked),
#到sleep结束后,线程进入到就绪(Runnable),等待调度。
#线程的状态
**#总结 ,**多个线程处于就绪状态,CPU具体调度由时间片决定。
#6,多线程–共享全局变量
#多线程可以共享全局变量,多进程之间内存独立,不能够共享全局变量,如果通信,使用Queue
#优点:多线程之间的数据交互变得简单,方便
#缺点:线程可以对全局变量进行修改,可能造成数据混乱(即线程非安全)
#加锁
#为了解决线程非安全所以进行了加锁
#加锁:互斥锁,当多个线程几乎同时修改某一个共享参数的时候就需要同步控制
#(1)创建锁 mutex=threading.Lock()
#(2)锁定 mutex.acquire([blocking])
#(3)释放 mutex.release()
#说明:(默认)blocking设置为True,则当前线程会阻塞,知道获取到这个锁为止。
#锁,其实是将并行操作变成了串行操作。
#总结:
#锁的好处:
#(1)确保了某段关键代码只能由一个线程从头到尾完成地执行。
#(2)阻止了多线程并发执行,包含锁的某段代码实质上只能以单线程模式执行。
#(3)由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁。
#死锁
#例如:两个线程(线程1是男,线程2是女),做菜
#资源:锅 铲 炒两个菜
#一个占有了锅资源,一个占有了铲资源,相互对持。
#解决方法:1,尽量减少资源占用时间,可以降低死锁的发生的概率。
#2,银行家算法
#Queue 的使用
#步骤1:导入模块
from multiprocessing import Queue
#步骤2;创建一个队列
q=Queue(3)#可接一个整数,表示队列的容量,如果省略表示不设上限
#步骤3:往队列里添加消息
#格式:put(self, obj, block=True, timeout=None):
#obj;消息对象
q.put('消息1')
q.put('消息2')
print(q.full())#Flase
q.put('消息3')
#判断队列状态的方法
q.full()#判断队列是否满足,返回一个布尔值,表示当前队列是否满了
print(q.full())#True
q.empty()##判断队列是否为空,返回一个布尔值,表示当前队列是否为空
q.qsize()#返回一个数值,表示当前队列的消息数量
#步骤4:从对列中取消息
value=q.get()
print(value)#消息1
value=q.get()
print(value)#消息2
#强存强取
from multiprocessing import Queue
q=Queue(3)
q.put(1)
q.put(2)
q.put(3)
#参数block:默认值为真,表示队列已满,程序阻塞。
#如果False,表示不需要阻塞,如果队列已满,将会抛出异常。
#参数 timeout 表示阻塞时间 ,单位为秒
try:
q.put(4,block=False)
q.put(4,block=False,timeout=1)
except:
print('消息队列已满,现有消息数量%s'%(q.qsize()))
print('---------')
#put的另一种形式
#q.put_nowait(5) 等价于 q.put(5,block=False)
try :
q.put_nowait(5)
except:
print('消息队列已满,现有消息数量%s' % (q.qsize()))
#推荐方式,想判断消息队列是否已经满了,再往里放
if not q.full():
q.put(6)
#--------------------------------分割线-------------------------------------
#取
#格式:def get(self, block=True, timeout=None):
print(q.get())
print(q.get())
print(q.get())#如果已空 ,不可再取
try:
print(q.get(block=False))
except:
print('消息队列已空,现有消息数量%s' % (q.qsize()))
q.get()#如果队列为空,一直阻塞
q.get(block=False)
q.get(block=True,timeout=2)
q.get_nowait()#强取 等价于 q.get(block=False)
#在读取信息时,判断是否为空
if not q.empty():
print(q.get())
print('..............')
#队列操作案例 需求:
#在父进程中创建两个子进程。一个往Queue里写数据,一个从Queue里读数据
from multiprocessing import Process
from multiprocessing import Queue
import time,random
#写进程
def write(q):
#由于进程之间的通信只能通过队列来完成,
#所以队列中最后一个元素‘Exit’为退出读取进程的标志
for value in ['a','b','c','d','Exit']:#E标志xit相当一个退出
print('Put %s from Queue'%value)
q.put(value)
time.sleep(random.random())
#读进程
def read(q):
while True:
if not q.empty():
value=q.get()#每次过q.get()就会读取一次,所以要把q.get
if value=='Exit':#赋予一个变量,用变量进行操作。
break
else:
print('Get %s from Queue'%(value))
time.sleep(random.random())
if __name__ == '__main__':
#创建一个队列
q=Queue()#不设上限
#创建2个进程
pw=Process(target=write,args=(q,))
pr=Process(target=read,args=(q,))
#启动
pw.start()
pr.start()
print('所有的读写进程结束')
#线程–文件下载
from threading import Thread
from urllib import request
def downloader(url):
file_name=url.split('/')[-1]
response=request.urlopen(url)
content=response.read()
with open(file_name,'wb') as f:
f.write(content)
if __name__ == '__main__':
# 主进程下面有一个主线程
url_list=['http://www.langlang2017.com/img/logo.png',
'http://www.langlang2017.com/img/langlang2.png']
#创建线程
thread_list=[]
for url in url_list:
t=Thread(target=downloader,args=(url,))
t.start()#启动线程
thread_list.append(t)
for t in thread_list:
t.join()
print('-----主进程执行完成-------')
#线程数量
from threading import Thread
import threading
import time
def sing():
for i in range(3):
print('唱第%d首歌'%i)
time.sleep(1)
def dance():
for i in range(3):
print('唱第%d首歌'%i)
time.sleep(1)
if __name__ == '__main__':
t1=Thread(target=sing)
t2=Thread(target=dance)
t1.start()
t2.start()
#查看线程的数量
while True:
count=len(threading.enumerate())
print('当前线程数量',count)
if count<=1:
break
#注意:至少得有一个主线程
#线程实现的第二种方式:继承
from threading import Thread
class MyThread(Thread):
def __init__(self,url):
Thread.__init__(self)
self.url=url
def run(self):
print('线程的业务逻辑代码',self.url)
if __name__ == '__main__':
t=MyThread(1)
t.start()
#共享全局变量
from threading import Thread
from multiprocessing import Process
g_num=100
def work1():
global g_num
for i in range(3):
g_num+=1
print('work1,g_num is %d'%(g_num))
def work2():
global g_num
for i in range(3):
g_num+=1
print('work2,g_num is %d'%(g_num))
if __name__ == '__main__':
t1=Thread(target=work1)
t1.start()
t2=Thread(target=work2)
t2.start()
#由于多线程可以共享全局变量,所以g_num又原来的100变成了106
#多进程之间内存独立,不能够共享全局变量。如果通信的话,使用Queue
p1=Process(target=work1)
p1.start()
p2=Process(target=work2)
p2.start()
#线程非安全 通过加锁来解决问题
from threading import Thread
from threading import Lock
g_num1=0
def work1():
global g_num1
for i in range(1000000):
mutex.acquire()#加锁
g_num1+=1
mutex.release()#解锁
def work2():
global g_num1
for i in range(1000000):
mutex.acquire()#加锁
g_num1+=1
mutex.release()#解锁
mutex=Lock()#创建锁 互斥
if __name__ == '__main__':
#进程
work1()
work2()
print('g_num',g_num1)
#线程
t1=Thread(target=work1)
t2=Thread(target=work2)
t1.start()
t2.start()
t1.join()
t2.join()
print('g_num',g_num1)
mNzZG4ubmV0L3lid18yNTY5,size_16,color_FFFFFF,t_70)