进程

操作系统

操作系统的定义:
操作系统是存在于硬件与软件之间,管理,协调,控制软件与硬件的交互.
操作系统的作用(面试会问)
1.将一些复杂的硬件操作封装成接口,便于使用.
2.合理的调度分配多个进程与CPU的关系让其有序化
如果没有操作系统,你去写一个程序,你只要完成两层即可.
第一层: 你要学会底层硬件:cpu,内存,磁盘是如何工作使用的.
第二层: 去调用这些底层的硬件.

进程

操作系统调度作用,将磁盘上的程序加载到内存,然后交由CPU去处理.一个CPU正在运行的一个程序,就叫开启了一个进程
进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu。
程序: 一堆静态的文件代码文件
两者区别:
    1.程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。
    2.进程是动态的,程序是静态的
  

多道技术

多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一个资源(比如cpu)的有序调度问题,解决方式即多路复用,多路复用分为时间上的复用和空间上的复用。

空间上的复用:将内存分成多个区域,一个内存可以执行多个进程
时间上的复用:当多个进程抢占一个CPU资源时,操作系统会使进程的执行变得合理有序

并发 和 并行

串行: 所有的任务一个一个的完成.执行完一个任务,在执行下一个任务
并发: 一个cpu执行多个进程
并行: 多个CPU执行多个进程
阻塞: CPU遇到io就会阻塞
非阻塞:没有IO,就叫非阻塞.
    
有效的提高了CPU的效率

进程的创建方式

1.
from multiprocessing import Process
import time
def tasf(name):
    print(f"{name}来了")
    time.sleep(2)
    print(f"{name}走了")

if __name__ == '__main__':                   #在Windows环境下 必须写main 与Windows操作系统有冲突
    p = Process(target=tasf,args=("小宋",))  #创建一个对象进程  args必须是个元祖  target:表示这个进程实例所调用对象;args:表示调用对象的位置参数元组;

    p.start()   #只是向操作系统发送一个开辟子进程的信号,然后执行下一行 这个操作系统接收到之后 会从内存中开辟一个子进程空间 然后把主进程的数据copy到子进程空间,开辟子进程的开销是很大的执行一个子进程,永远会先打印主进程

2.
from multiprocessing import Process
import time
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()   #父类中找
        self.name = name
    def run(self): #  如果不是run 回去父类中找,父类中没有run方法,所以就不会执行,所以必须是run
        print(f'{self.name} is running')
        time.sleep(2)
        print(f'{self.name} is gone')
if __name__ == '__main__':
    p = MyProcess('你')
    p.start()   #会执行一个run方法 类的约束
    print('=====主')
    # 一个py文件是一个主进程

验证进程的空间隔离

#进程之间的数据是隔离的,数据不共享
from multiprocessing import Process
n = 100
def work():
    global n
    n = 0
    print('子进程内:',n)
if __name__ == '__main__':
    p= Process(target=work)
    p.start()
    p.join()
    print('主进程内:',n)
子进程内: 0
主进程内: 100
#等待子进程执行完后,如果数据是共享的话,子进程就通过global将n改为0,但是通过结果,结果仍是主进程n = 100 子进程n = 0
# 说明子进程对n 的修改没有在主进程中生效 说明他们之间的数据是隔离的

进程的 p i d

import os
print(f'子进程:{os.getpid()}')  #获取子进程id  (Pycharm是主进程)
print(f'主进程:{os.getppid()}')  #获取主进程id  (Pycharm是主进程)

进程join

from multiprocessing import Process
import time
def task(sec,name):
    print(f'{name}is running')
    time.sleep(sec)
    print(f'{name}is gone')
if __name__ == '__main__':
    strat_time = time.time()
    p = Process(target=task,args=(3,"你"))
    p1 = Process(target=task,args=(4,"我"))
    p2= Process(target=task,args=(1,"他"))
    p.start()
    p1.start()
    p2.start()

    p.join()#执行到这时,睡3秒,由于是并行或并发,在这3秒中会先执行 p2的'他',在执行p的'你' 执行完后执行14782,在执行p1的'我' 时间的合理利用,提高CPU效率
    print(14782)
    p1.join()
    p2.join()

    #join执行完之后才执行join下边的代码
    print(f"{time.time()-strat_time}")
    
****************************************************************************************************
对上一个代码的优化
from multiprocessing import Process
import time
def sendmail(n):
    time.sleep(1)
    print(f'发送邮件{n}')
if __name__ == '__main__':
    l =[]
    for i in range(10):
        p = Process(target=sendmail,args=(i,))
        l.append(p)
        p.start()
    for p in l:
        p.join()
    print('所有的邮件都已经发送了')
    
****************************************************************************************************
from multiprocessing import Process
import time
def send(num):
    time.sleep(0.5)
    print(f"发送邮件{num}")
if __name__ == '__main__':
    for i in range(10):
        p = Process(target=send,args=(i,))
        p.start()
        p.join()
    print('所有的邮件都已经发送了')

守护进程

主进程创建守护进程
  其一:守护进程会在主进程代码执行结束后就终止
  其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

from multiprocessing import Process
import time
def func():
    print(123)
    time.sleep(1)
    print('end123')
def foo():
    print(456)
    time.sleep(2)
    print('end456')
if __name__ == '__main__':
    p1 = Process(target=func)
    p2 = Process(target=foo)
    p1.daemon = True #守护进程p1
    p1.start()       #执行p1的子进程时,子进程需要开辟内存空间,需要耗费时间,所以先执行 print('----main----')
                     #所以执行完 print('----main----')之后,子进程将不执行,由于p2没有被守护,所以会执行p2
    p2.start()  
    print('----main----')
    
----main----
456
end456

进程对象的其他属性

********************************************terminate************************************************
1.
from multiprocessing import Process
import time
def task(name):
    print(f"{name} is running")
    print(f"{name} is gone")
if __name__ == '__main__':
    p = Process(target=task,args=('常新',),name = 'Alex')
    p.start()
    time.sleep(1)   #睡1秒,足够时间执行子进程中的内容
    p.terminate()   #杀死进程
    p.join()        #当执行完子进程后执行以下的内容
    print(p.name)
#常新 is running
#常新 is gone
#Alex

2.
from multiprocessing import Process
import time
def task(name):
    print(f"{name} is running")
    # time.sleep(2)
    print(f"{name} is gone")
if __name__ == '__main__':
    p = Process(target=task,args=('常新',),name = 'Alex')
    p.start()
    p.terminate()   #直接杀死子进程
    p.join()
    print(p.name)   #Alex

3.
from multiprocessing import Process
import time
def task(name):
    print(f"{name} is running")
    time.sleep(2)   #睡2秒
    print(f"{name} is gone")
if __name__ == '__main__':
    p = Process(target=task,args=('常新',),name = 'Alex')
    p.start()
    time.sleep(1)    #睡1秒  先执行子进程的 print(f"{name} is running") 接着执行,发现又睡2秒,但这一步是睡眠1秒,所以向下执行p.terminate() 结束子进程的 print(f"{name} is gone") 
    p.terminate()
    p.join()
    print(p.name)
#常新 is running
#Alex

 4.
from multiprocessing import Process
import time
def task(name):
    print(f"{name} is running")
    time.sleep(2)   #睡2秒
    print(f"{name} is gone")
if __name__ == '__main__':
    p = Process(target=task,args=('常新',),name = 'Alex')
    p.start()
    time.sleep(3)    #睡3秒  先执行子进程的 print(f"{name} is running") 在睡眠2秒,此时这步还剩1秒,继续执行子进程的print(f"{name} is gone") 所以没有杀死子进程,子进程就已经执行完了
    p.terminate()
    p.join()
    print(p.name)
#常新 is running
#常新 is gone
#Alex

********************************************is_alive*************************************************

from multiprocessing import Process
import time
import os
def task(n):
    print(1233)
    time.sleep(5)
    print(f"{n} is running {os.getpid()},{os.getppid()}")
if __name__ == '__main__':
    p1 = Process(target=task,args=(1,))
    p1.start()
    p1.terminate()   #只是给操作系统发送信号,关闭子进程,交给操作系统,不知道具体什么时候什么时候关闭
    #time.sleep(0.00000000000000000000000001)  #极限时间
    time.sleep(1)    #睡眠1秒,在睡眠1秒过程中,先执行主进程print('主') ,接着执行print(p1.is_alive())
    print("主")
    print(p1.is_alive()) #判断子进程是否还存活 
#主
#False

僵尸进程和孤儿进程

主进程时刻监测子进程的运行状态,当子进程结束之后,一段时间之内,将子进程进行回收

僵尸进程(有害): 所有的子进程结束之后,在被主进程回收之前,都会进入僵尸进程状态
孤儿进程: 父进程由于某种原因结束了,但是你的子进程还在运行中,这样你的这些子进程就成了孤儿进程.你的父进程如果结束了,你的所有的孤儿进程就会被init进程的回收,init就变成了你的父进程,对你进行回收.
回收内容:进程号 运行状态 时间
    
僵尸进程的危害:如果父进程不对僵尸进程进行回收(wait/waitpid),产生大量的僵尸进程,这样就会占用内存,占用进程pid号.

僵尸进程如何解决?
父进程产生了大量子进程,但是不回收,这样就会形成大量的僵尸进程,解决方式就是直接杀死父进程,将所有的僵尸进程变成孤儿进程进程,由init进行回收.

锁和队列

#文件db的内容为:{"count":1}
#注意一定要用双引号,不然json无法识别
#并发运行,效率高,但竞争写同一文件,数据写入错乱
from multiprocessing import Process,Lock
import time,json,random
def search():
    dic=json.load(open('db'))
    print('33[43m剩余票数%s33[0m' %dic['count'])

def get():
    dic=json.load(open('db'))
    time.sleep(0.1) #模拟读数据的网络延迟
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(0.2) #模拟写数据的网络延迟
        json.dump(dic,open('db','w'))
        print('33[43m购票成功33[0m')

def task():
    search()
    get()

if __name__ == '__main__':
    for i in range(100): #模拟并发100个客户端抢票
        p=Process(target=task)
        p.start()
        
加锁
#文件db的内容为:{"count":5}
#注意一定要用双引号,不然json无法识别
#并发运行,效率高,但竞争写同一文件,数据写入错乱
from multiprocessing import Process,Lock
import time,json,random
def search():
    dic=json.load(open('db'))
    print('33[43m剩余票数%s33[0m' %dic['count'])

def get():
    dic=json.load(open('db'))
    time.sleep(random.random()) #模拟读数据的网络延迟
    if dic['count'] >0:
        dic['count']-=1
        time.sleep(random.random()) #模拟写数据的网络延迟
        json.dump(dic,open('db','w'))
        print('33[32m购票成功33[0m')
    else:
        print('33[31m购票失败33[0m')

def task(lock):
    search()
    lock.acquire()
    get()
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    for i in range(100): #模拟并发100个客户端抢票
        p=Process(target=task,args=(lock,))
        p.start()
#加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。


***队列***
什么是队列? ---> 队列就是存在于内存中的一个容器,它的一个特点:队列的特性就是FIFO,完全支持先进先出的原则 进程批次之间互相隔离,要实现进程间通信(IPC),multiprocessing模块中的队列方式可以实现
创建队列的类(底层就是一管道和锁定的方式实现) Queue([maxsize]) : 创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实多进程之间的数据传递
    
from multiprocessing import Queue
q = Queue(3)
q.put(1)
q.put(2)
q.put(3)      # q.put(4) # 当队列数据已经达到上限,再插入数据的时候,程序就会阻塞住
print(q.get()) 
print(q.get()) 
print(q.get()) 
print(q.get()) # 当队列中的数据取完之后,程序也会阻塞住

maxsize() q = Queue(3) 数据量不易过大,队列主要存放精简的重要的数据 
block 默认值是True,当你插入的数据量超过大限度,默认阻塞,如果block = False 数据超过大限度,不阻塞了 直接报错. timeout = 3 延时报错,超过3秒再不put数据,就会报

# 用进程通信队列模拟实例 
from multiprocessing import Process from multiprocessing import Queue import os
def task(q):
    try:
        q.put(f'{os.getpid()}',block=False)
    except Exception:
        return
if __name__ == '__main__':
    q = Queue(10)
    for i in range(100):
        p = Process(target=task,args=(q,))# 给CPU发送命令,开启子进程会有一定时间的延迟,在这个时间段内,主进程会继续执行  
        p.start()
    for i in range(1,11):  # 如果循环次数再多,会取到更多的值        				
        print(f'排名为{i}的用户:{q.get()}')

生产者与消费者模型

生产者  消费者  队列    为了平衡
如果没有容器,生产者与消费者增强耦合性,不合理.所以要有一个容器,缓冲区,平衡生产力和消费力. 
from multiprocessing import Process,Queue
import time,random,os
def scz(q):
    for i in range(1,6):
        time.sleep(random.randint(1,3))
        res = f'第{i}个包子'
        q.put(res)
        print(f'{os.getppid()}生产了{res}')
def xfz(q):
    while 1:
        try:
            food = q.get(timeout=3)
            time.sleep(random.randint(1,2))
            print(f"{os.getpid()}吃了{food}")
        except Exception:
            return
if __name__ == '__main__':
    q = Queue()
    p = Process(target=scz,args=(q,))
    p1 = Process(target=xfz,args=(q,))
    p.start()
    p1.start()
原文地址:https://www.cnblogs.com/tangjian219/p/11414405.html