进程 队列 线程 加锁 死锁

进程通信--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)

  • 8
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值