进程的开启方式 进程的join方法 进程间的内存隔离 其他相关方法 守护进程 互斥锁

#创建进程的方式一
from multiprocessing import Process
import time

def task(name):
    print('%s is running'%name)
    time.sleep(2)
    print('%s is over'%name)

'''
# 注意:在window系统里,创建进程会将代码以模块的方式从头到尾加载一遍
# 创建进程的代码块要写在 if __name__ == '__main__': 里面,避免出错
# 强调:函数名一旦加括号,执行优先级最高,会马上执行。
'''

if __name__ == '__main__':
    p = Process(target=task,args=('michael',)) #这句话实例了一个Process对象
    p.start()   #告诉操作系统创建一个进程
    print('我是主进程!')
    
#实际输出的结果:我是主进程!
                 #michael is running
                 #michael is over
#解释:操作系统创建进程的时间比代码运行的速度要慢,所以先将主进程的输出结果打印出来



#创建进程的方式二
from multiprocessing import Process
import time

class MyProcess(Process):

    def __init__(self,name):
        super().__init__()
        self.name = name
    #必须写run方法
    def run(self):
        print('%s is running'%self.name)
        time.sleep(2)
        print('%s is over'%self.name)

if __name__ == '__main__':
    obj = MyProcess('michael')
    obj.start()
    print('我是主进程!')

 

join方法

from multiprocessing import Process
import time

def task(name,n):
    print('%s is running'%name)
    time.sleep(n)
    print('%s is over'%name)

# if __name__ == '__main__':
#     p1 = Process(target=task,args=('egon1',1))
#     p2 = Process(target=task,args=('egon2',2))
#     p3 = Process(target=task,args=('egon3',3))
#     start_time = time.time()  #系统创建进程的时间
#     p1.start()  #这行代码只是告诉操作系统需要创建进程
#     p2.start()
#     p3.start()
#     p1.join()    #join的作用: 让主进程等待子进程结束,然后再运行主进程,并不会影响子进程的运行
#     p2.join()
#     p3.join()
#     print('我是主进程',time.time()-start_time)  #记录主进程等待的时间

# 上面冗余的代码可以简化
if __name__ == '__main__':
    start_time = time.time()
    p_list = []
    for i in range(3):
        p = Process(target=task,args=('子进程%s'%i,i))
        p.start()
        p_list.append(p)
    for p in p_list:
        p.join()
    print('主进程',time.time()-start_time)

  

#进程间数据隔离
from multiprocessing import Process
x = 100
def task():
    global x
    x = 0

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()  #加上join 为了确保先运行子进程
    print('主进程',x)   #主进程 100
#结果说明:每个进程之间的数据是彼此隔离的!

  

#进程对象其他相关方法
from multiprocessing import Process
import time
import os

def task():
    print('子进程自己的pid',os.getpid())
    time.sleep(3)
    print('子进程父级的pid',os.getppid())

#is_alive的使用   判断子进程是否存活
if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print(p.is_alive())  #True  此时的子进程是存在的
    p.join(4)   #join()里的参数需要大于sleep的参数,不然还是会自动运行,当没有参数时,默认等子进程执行完
    print(p.is_alive())  #False   is_alive() 放在join后会自动将子进程销毁,因此不存在
    print('我是主进程')
    print(p.pid)   #查看子进程自己的pid

# termininate的使用  杀死子进程
if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.terminate() #关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
    print(p.is_alive())  #True
    p.join()
    print('我是主进程!')
    print(p.is_alive())  #False

  

#守护进程
主进程创建守护进程:
    特点1:守护进程会在主进程代码执行结束后就终止
    特点2:守护进程内无法再开启子进程,否则会抛出异常

例子1:
from multiprocessing import Process
import time
def task(name):
    print('%s正活着'%name)
    time.sleep(2)
    print('%s正在死亡'%name)

if __name__ == '__main__':
    p = Process(target=task,args=('子进程',))
    p.daemon = True #一定要在p.start前设置,设置子线程p为主线程的守护进程,禁止p创建子线程
    #并且父进程代码执行结束,p也将终止运行,由于操作系统的处理时间较慢,正常情况下都是直接执行完父进程就结束了
    p.start()
    # p.daemon = True 将daemon放在 start 后面会报错!
    print('主进程正在死亡')



例子2:
from multiprocessing import Process
from threading import Thread
import time
def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(1)
    print("end456")

if __name__ == '__main__':

    p1=Process(target=foo)
    p2=Process(target=bar)
    p1.daemon=True
    p1.start()
    p2.start()
    # p1.join()   #当加上了join后,子进程会正常执行,此时的daemon好像不起作用了!下面有详解!
    print("main-------")

  

#join 与daemon之间的关系

1 Python 默认参数创建线程后,不管主线程是否执行完毕,都会等待子线程执行完毕才一起退出,有无join结果一样 
2 如果创建线程,并且设置了daemon为true,即thread.setDaemon(True), 则主线程执行完毕后自动退出,
        不会等待子线程的执行结果。而且随着主线程退出,子线程也消亡。
3 join方法的作用是阻塞,等待子线程结束,join方法有一个参数是timeout,即如果主线程等待timeout,
        子线程还没有结束,则主线程强制结束子线程。 
4 如果线程daemon属性为False, 则join里的timeout参数无效。主线程会一直等待子线程结束。 
5 如果线程daemon属性为True, 则join里的timeout参数是有效的, 主线程会等待timeout时间后,结束子线程。
    此处有一个坑,即如果同时有N个子线程join(timeout),那么实际上主线程会等待的超时时间最长为 N timeout, 
    因为每个子线程的超时开始时刻是上一个子线程超时结束的时刻。

  

#僵尸进程与孤儿进程
'''回收子进程的pid等信息的两种方式:
    1、父进程正常结束
    2、join方法
'''

  

互斥锁
#模拟抢票
from multiprocessing import Process,Lock
import json
import time
import random

def search(i):
    with open('info','r',encoding='utf-8') as f:
        data = json.load(f)
    print('剩余票数为%s'%data.get('ticket'))

def buy(i):
    #买票前还需要查看是否还有票!
    with open('info','r',encoding='utf-8')as f:
        data = json.load(f)
    #模拟网络延迟
    time.sleep(random.randint(1,3))
    if data.get('ticket') > 0:
        data['ticket'] -= 1 #买票,库存减一
        #将更新的信息重新写入文件
        with open('info','w',encoding='utf-8')as f:
            json.dump(data,f)
        print('用户%s抢票成功'%i)
    else:
        print('没有余票,用户%s抢票失败!'%i)

def run(i,mutex):
    search(i)    #所有的进程查询的余票数为一致的,大家的起点一致     这一步应该放入到mutex.acquire下
    mutex.acquire()  #抢锁 一把锁只能被一个人抢到,其他人等待锁被释放
    buy(i)
    mutex.release()  #释放锁,其他人又处于同一地步了

if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=run,args=(i,mutex))
        p.start() #产生10个子进程

 

互斥锁补充:不要随便使用
    特点:牺牲了效率但是保证了数据的安全,解决了多个进程操作同一分数据,造成数据不安全的情况。

    锁一定要在主进程中创建,给子进程使用:
    加锁会将并发变成串行
    锁通常用在对数据操作的部分,并不是对进程全程加锁        

  

 

#小点:
from multiprocessing import Process
import time, os
def task():
    print('%s is running' % os.getpid())
    # time.sleep(3)
if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print(p.is_alive())  #True
    p.join()  # 等待进程p结束后,join函数内部会发送系统调用wait,去告诉操作系统回收掉进程p的id号
    print(p.pid)  # ???此时能否看到子进程p的id号    可以看到
    print(p.is_alive())  #False
    print('主')
    print(p.pid)   #依然存在
'''
上述问题的解释:
p.join()是向操作系统发送请求,告知操作系统 子进程p的id号不需要再占用了,回收就可以,
此时在父进程内还可以看到p.pid,但此时的p.pid是一个无意义的id号,因为操作系统已经将该编号回收
'''

  

 

原文地址:https://www.cnblogs.com/changwenjun-666/p/10821023.html