进程process

进程process

1.基本使用

2.同步子父进程join

3.自定义创建进程(带有参数)

4.守护进程

5.互斥锁(lock)

6.信号量(semphore)

7.事件 (Event)

8.进程队列(Queue)

9.生产者消费者模型

10.进程之间共享数据(Manager)

 

1.基本使用

(1) 进程的使用

def func():
    # 1.子进程id:3561,2.父进程id:3560
    print("1.子进程id:{},2.父进程id:{}".format(os.getpid(),os.getppid()))

if __name__ == "__main__":
    # 创建子进程 ,返回进程对象
    p = Process(target=func)
    # 调用子进程
    p.start()
    
    # 3.主进程id:3560,4.父进程id:3327
    print("3.主进程id:{},4.父进程id:{}".format(os.getpid(),os.getppid()))

(2) 创建带有参数的进程

def func(n):
    time.sleep(1)
    for i in range(1,n+1): # 0 ~ n-1
        print(i)
        print("1.子进程id:{},2.父进程id:{}".format(os.getpid(),os.getppid()))
        
if __name__ == "__main__":
    n = 6
    # target=指定任务  args = 参数元组
    p = Process(target=func , args=(n,))
    p.start()
    
    for i in range(1,n+1):
        print("*" * i)

(3) 进程之间的数据彼此隔离

total = 100
def func():
    global total
    total +=1
    print(total)
    
if __name__ == "__main__":
    p = Process(target=func)
    p.start()
    
    time.sleep(1)
    print(total)

(4) 进程之间的异步性

"""
1.多个进程之间是异步的并发程序,因为cpu调度策略问题,不一定先执行哪一个任务
默认来看,主进程执行速度稍快于子进程,因为子进程创建时,要分配空间资源可能会阻塞
阻塞态,cpu会立刻切换任务,以让程序整体的速度效率最大化

2.默认主进程要等待所有的子进程执行结束之后,在统一关闭程序,释放资源
若不等待,子进程可能不停的在系统的后台占用cpu和内存资源形成僵尸进程.
为了方便进程的管理,主进程默认等待子进程.在统一关闭程序;
"""

def func(n):
    print("1.子进程id:{},2.父进程id:{}".format(os.getpid(),os.getppid()) , n )

if __name__ == "__main__":
    for i in range(1,11):
        p = Process(target=func,args=(i,))
        p.start()

    print("主进程执行结束了 ... " , os.getpid() )

 

2.同步子父进程join

(1) join 的基本使用

def func():
    print("发送第一封邮件 :  亲爱得领导,你在么?")    

if __name__ == "__main__":
    p = Process(target=func)
    p.start()
    # time.sleep(0.1)
    p.join()
    print("发送第二封邮件 :  我想说,工资一个月给我涨到6万")

 

(2) 多进程场景中的join

def func(i):
    time.sleep(1)
    print("发送第一封邮件{} :  我的亲亲领导,你在么?".format(i))
    
if __name__ == "__main__":
    lst = []
    for i in range(1,11):
        p = Process(target=func,args=(i,))
        p.start()
        # join 写在里面会导致程序变成同步
        lst.append(p)
        
    # 把所有的进程对象都放在列表中,统一使用.join进行管理;
    for i in lst:
        i.join()
        
        
    print("发送第二封邮件 :  我想说,工资一个月给我涨到6万")

3.自定义创建进程(带有参数)

class MyProcess(Process):

    def __init__(self,name):
        # 手动调用一下父类的构造方法,完成系统成员的初始化;
        super().__init__()
        self.name = name
    
    def run(self):
        print("1.子进程id:{},2.父进程id:{}".format(os.getpid(),os.getppid()))
        print(self.name)
        
if __name__ == "__main__":
    p = MyProcess("我是参数")
    p.start()

4.守护进程

(1) 基本语法

"""守护进程守护的是主进程,当主进程所有代码执行完毕之后,立刻强制杀死守护进程;"""
def func():
    # time.sleep(1)
    print("start... 当前的子进程")
    print("end ...  当前的子进程")


if __name__ == "__main__":
    p = Process(target=func)
    # 在进程启动之前,设置守护进程
    p.daemon = True    
    p.start()    

    print("主进程执行结束 ... ")

(2) 多个子进程的守护场景

def func1():
    print("start ... func1 执行当前子进程 ... ")
    print("end ...   func1 结束当前子进程 ... ")
    
def func2():
    count = 1
    while True:
        print("*" * count)
        time.sleep(1)
        count += 1

if __name__ == "__main__":
    p1 = Process(target=func1)
    p2 = Process(target=func2)
    
    # 把p2这个进程变成守护进程;
    p2.daemon = True
    p1.start()
    p2.start()
    
    print("主进程执行结束 ... ")

 

(3) 守护进程用途: 监控报活

def alive():
    while True:
        print("3号服务器向总监控服务器发送报活信息: i am ok~")
        time.sleep(1)
        
def func():
    while True:
        try:
            print("3号服务器负责抗住3万用户量的并发访问...")
            time.sleep(3)
            
            # 主动抛出执行错误的异常,触发except分支
            raise RuntimeError            
            
        except:
            print("3号服务器爆炸了")
            break
            
            
if __name__ == "__main__":
    p1 = Process(target=alive)
    p2 = Process(target=func)

    p1.daemon = True
    p1.start()
    p2.start()
    
    # 必须等待p2这个子进程执行完毕之后,再放行主进程下面的代码
    # 下面主进程代码执行结束,立刻杀死守护进程,失去了报活功能;
    p2.join()        
    print("主进程执行结束  .... ")

5.互斥锁(lock)

(1)基本知识

""" 上锁和解锁是一对, 连续上锁不解锁是死锁 ,只有在解锁的状态下,其他进程才有机会上锁 """

# 创建一把锁
lock = Lock()
# 上锁
lock.acquire()
# lock.acquire() # 连续上锁,造成了死锁现象;
print("111")
# 解锁
lock.release()

(2)12306 抢票软件

import json,time,random
"""ticket文件中用字典形式存储{"count": 0}"""
# 1.读写数据库当中的票数
def wr_info(sign , dic=None):
    if sign == "r":
        with open("ticket",mode="r",encoding="utf-8") as fp:
            dic = json.load(fp)
        return dic
        
    elif sign == "w":
        with open("ticket",mode="w",encoding="utf-8") as fp:
            json.dump(dic,fp)

# dic = wr_info("w",dic={"count":0})
# print(dic , type(dic) )

# 2.执行抢票的方法
def get_ticket(person):
    # 先获取数据库中实际票数
    dic = wr_info("r")
    
    # 模拟一下网络延迟
    time.sleep(random.uniform(0.1,0.7))
    
    # 判断票数
    if dic["count"] > 0:
        print("{}抢到票了".format(person))
        # 抢到票后,让当前票数减1
        dic["count"] -= 1
        # 更新数据库中的票数
        wr_info("w",dic)
    else:
        print("{}没有抢到票哦".format(person))
        
# 3.对抢票和读写票数做一个统一的调用
def main(person,lock):
    
    # 查看剩余票数
    dic = wr_info("r")
    print("{}查看票数剩余: {}".format(person,dic["count"]))
    
    # 上锁
    lock.acquire()
    # 开始抢票
    get_ticket(person)
    # 解锁 
    lock.release()
    
if __name__ == "__main__":
    lock = Lock()
    lst = ["梁新宇","康裕康","张保张","于朝志","薛宇健","韩瑞瑞","假摔先","刘子涛","黎明辉","赵凤勇"]
    for i in lst:
        p = Process(    target=main,args=(  i  , lock  )   )
        p.start()
    
"""
创建进程,开始抢票是异步并发程序
直到开始抢票的时候,变成同步程序,
先抢到锁资源的先执行,后抢到锁资源的后执行;
按照顺序依次执行;是同步程序;
"""

6.信号量(semphore)

# ### 信号量 Semaphore 本质上就是锁,只不过是多个进程上多把锁,可以控制上锁的数量
"""Semaphore = lock + 数量 """
from multiprocessing import Semaphore , Process
import time , random
"""
    # 同一时间允许多个进程上5把锁
    sem = Semaphore(5)
    #上锁
    sem.acquire()
    print("执行操作 ... ")
    #解锁
    sem.release()
"""

def singsong_ktv(person,sem):
    # 上锁
    sem.acquire()
    
    print("{}进入了唱吧ktv , 正在唱歌 ~".format(person))
    # 唱一段时间
    time.sleep( random.randrange(4,8) ) # 4 5 6 7
    
    print("{}离开了唱吧ktv , 唱完了 ... ".format(person))
    
    # 解锁
    sem.release()

if __name__ == "__main__":
    sem = Semaphore(5)
    lst = ["赵凤勇" , "沈思雨", "赵万里" , "张宇" , "假率先" , "孙杰龙" , "陈璐" , "王雨涵" , "杨元涛" , "刘一凤"   ]
    for i  in lst:
        p = Process(target=singsong_ktv , args = (i , sem))
        p.start()

"""
# 总结: Semaphore 可以设置上锁的数量 , 同一时间上多把锁
创建进程时,是异步并发,执行任务时,是同步程序;
"""

7.事件 (Event)

(1)基本知识

# 阻塞事件 :
    e = Event()生成事件对象e   
    e.wait()动态给程序加阻塞 , 程序当中是否加阻塞完全取决于该对象中的is_set() [默认返回值是False]
    # 如果是True  不加阻塞
    # 如果是False 加阻塞

# 控制这个属性的值
    # set()方法     将这个属性的值改成True
    # clear()方法   将这个属性的值改成False
    # is_set()方法  判断当前的属性是否为True  (默认上来是False)

(2)红绿灯效果

from multiprocessing import Process,Event
import time , random
# ### 模拟经典红绿灯效果
# 红绿灯切换
def traffic_light(e):
    print("红灯亮")
    while True:
        
        if e.is_set():
            # 绿灯状态 -> 切红灯
            time.sleep(1)
            print("红灯亮")
            # True => False
            e.clear()
        else:
            # 红灯状态 -> 切绿灯
            time.sleep(1)
            print("绿灯亮")
            # False => True
            e.set()

# 车的状态
def car(e,i):
    # 判断是否是红灯,如果是加上wait阻塞
    if not e.is_set():
        print("car{} 在等待 ... ".format(i))
        e.wait()
        
    # 否则不是,代表绿灯通行;
    print("car{} 通行了 ... ".format(i))
        
"""    
# 1.红绿灯一直开启
if __name__ == "__main__":
    e = Event()
    # 创建交通灯
    p1 = Process(target=traffic_light , args=(e,))
    p1.start()

    # 创建小车进程
    for i in range(1,21):
        time.sleep(random.randrange(2))
        p2 = Process(target=car , args=(e,i))
        p2.start()
"""

# 2.没有车的时,把红绿灯自动关闭
if __name__ == "__main__":

    lst = []
    e = Event()
    
    # 创建交通灯
    p1 = Process(target=traffic_light , args=(e,))
    
    # 设置红绿灯为守护进程
    p1.daemon = True
    p1.start()

    # 创建小车进程
    for i in range(1,21):
        time.sleep(random.randrange(2))
        p2 = Process(target=car , args=(e,i))
        lst.append(p2)
        p2.start()
        
    # 让所有的小车全部跑完,把红绿灯炸飞
    print(lst)
    for i in lst:
        i.join()

    print("关闭成功 .... ")

8.进程队列(Queue)

(1)基本知识

from multiprocessing import Process,Queue
# 引入线程模块; 为了捕捉queue.Empty异常;
import queue


# 1.基本语法
"""顺序: 先进先出,后进后出"""
# 创建进程队列
q = Queue()

# put() 存放
q.put(1)
q.put(2)
q.put(3)

# get() 获取
"""在获取不到任何数据时,会出现阻塞"""
# print(  q.get()  )
# print(  q.get()  )
# print(  q.get()  )
# print(  q.get()  )

# get_nowait() 拿不到数据报异常
"""[windows]效果正常  [linux]不兼容"""
try:
    print(  q.get_nowait()  )
    print(  q.get_nowait()  )
    print(  q.get_nowait()  )
    print(  q.get_nowait()  )
except : #queue.Empty
    pass

# put_nowait() 非阻塞版本的put
# 设置当前队列最大长度为3 ( 元素个数最多是3个 )
"""在指定队列长度的情况下,如果塞入过多的数据,会导致阻塞"""
# q2 = Queue(3)
# q2.put(111)
# q2.put(222)
# q2.put(333)
# q2.put(444)

"""使用put_nowait 在队列已满的情况下,塞入数据会直接报错"""
q2 = Queue(3)
try:
    q2.put_nowait(111)
    q2.put_nowait(222)
    q2.put_nowait(333)
    q2.put_nowait(444)
except:
    pass

(2)进程间的通信IPC

def func(q):
    # 2.子进程获取主进程存放的数据
    res = q.get()
    print(res,"<22>")
    # 3.子进程中存放数据
    q.put("小明")

if __name__ == "__main__":
    q3 = Queue()
    p = Process(target=func,args=(q3,))
    p.start()

    # 1.主进程存入数据
    q3.put("小绿")
    
    # 为了等待子进程把数据存放队列后,主进程在获取数据;
    p.join()
    
    # 4.主进程获取子进程存放的数据
    print(q3.get())

9.生产者消费者模型

(1)基本知识

"""
# 爬虫案例
1号进程负责抓取其他多个网站中相关的关键字信息,正则匹配到队列中存储(mysql)
2号进程负责把队列中的内容拿取出来,将经过修饰后的内容布局到自个的网站中

1号进程可以理解成生产者
2号进程可以理解成消费者

从程序上来看 
    生产者负责存储数据 (put)
    消费者负责获取数据 (get)
    
生产者和消费者比较理想的模型:
    生产多少,消费多少 . 生产数据的速度 和 消费数据的速度 相对一致    
"""
提示:qut(None)

(2)JoinableQueue 队列

"""
put 存放  
get 获取  
task_done 计算器属性值-1  
join 配合task_done来使用 , 阻塞

put 一次数据, 队列的内置计数器属性值+1
get 一次数据, 通过task_done让队列的内置计数器属性值-1
join: 会根据队列计数器的属性值来判断是否阻塞或者放行
    队列计数器属性是 等于 0 ,  代码不阻塞放行
    队列计数器属性是 不等 0 ,  意味着代码阻塞
"""

# ### 使用JoinableQueue 改造生产着消费者模型
from multiprocessing import Process,JoinableQueue
import time,random
# 消费者模型
def consumer(q,name):
    while True:
        # 获取队列中的数据
        food = q.get()
        time.sleep(random.uniform(0.1,1))
        print("{}吃了{}".format(name,food))
        # 让队列的内置计数器属性-1
        q.task_done()


# 生产者模型
def producer(q,name,food):
    for i in range(5):
        time.sleep(random.uniform(0.1,1))
        
        # 展示生产的数据
        print(  "{}生产了{}".format(  name , food+str(i)  )   )
        # 存储生产的数据在队列中
        q.put(food+str(i))
    
if __name__ == "__main__":
    q = JoinableQueue()
    p1 = Process(  target=consumer,args=(q , "小明")  )
    p2 = Process(  target=producer,args=(q , "小红" , "香蕉" )  )
    
    p1.daemon = True
    
    p1.start()
    p2.start()
    
    p2.join()
    # 必须等待队列中的所有数据全部消费完毕,再放行
    q.join()

    print("程序结束 ... ")

10.进程之间共享数据(Manager)

# ### Manager ( list 列表  ,  dict 字典 ) 进程之间共享数据
from multiprocessing import Process , Manager ,Lock

def mywork(data,lock):
    # 共享字典
    """
    lock.acquire()
    data["count"] -= 10
    lock.release()
    """
    
    # 共享列表
    data[0] += 1
    
    
if __name__ == "__main__":
    lst = []
    m = Manager()
    lock = Lock()
    # 多进程中的共享字典
    # data = m.dict(  {"count":5000}  )
    # print(data , type(data) )
    # 多进程中的共享列表
    data =  m.list( [100,200,300] )
    # print(data , type(data) )
    """"""
    # 进程数超过1000,处理该数据,死机(谨慎操作)
    for i in range(10):
        p = Process(target=mywork,args=(data,lock))
        p.start()
        lst.append(p)
        
    # 必须等待子进程所有计算完毕之后,再去打印该字典,否则报错;
    for i in lst:
        i.join()
        
    print(data)

 

回到顶部 

 

posted @ 2020-11-14 14:13  流连、陌往返  阅读(49)  评论(0)    收藏  举报
点我跳转百度