Python入门学习 DAY34 进程

Python入门学习

DAY34

今日内容:

1. 开启子进程的两种方式   

2. 进程之间的内存隔离 

3. 进程对象相关属性 

4. 守护进程

5. 互斥锁

6. 僵尸进程与孤儿进程

进程原理参考:http://www.cnblogs.com/linhaifeng/articles/7430066.html#_label4

开启子进程的两种方式 

方式一:

from multiprocessing import Process

import time

def task(name):
    print('%s is running' % name)
    time.sleep(3)  # 模拟子进程生命周期
    print('%s is done' % name)

#在windows系统上,开启子进程的操作必须放到if __name__ == '__main__':的子代码中
if __name__ == '__main__':
    p = Process(target=task,args=('subprocess1',))  # 注意,args必须传入元祖
    p.start()  # 想操作系统发送一个开启子进程的信号
    print('主进程 is running...')

 方式二:

from multiprocessing import Process

import time

class Myprocess(Process):    # 自定义一个process类,基础Process
    
    def __init__(self,name):
        super().__init__()
        self.name=name

    def run(self):
        print('%s is running' % self.name)
        time.sleep(3)
        print('%s is done' % self.name)

if __name__ == '__main__':
    p = Myprocess('subprocess1')
    p.start()                     # 当启动子进程时,自动运行run()
    print('主程序 is running...')

进程之间的内存隔离  

from multiprocessing import Process

n = 100

def task():
    global n
    n = 0
    print(n)          # 0

if __name__ == '__main__':
    p = Process(target = task)
    p.start()
    print(n)       # 100

进程对象相关属性 

1. join方法的使用

join:让主进程在原地等待,等待子进程运行完毕,不会影响子进程的执行

from multiprocessing import Process

import  time

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


if __name__ == '__main__':
    start = time.time()
    p_l=[]

    for i in range(1,4):   # 创建多个子进程
        p = Process(target=task,args=('子%s'%i,i))
        p_l.append(p)
        p.start()

    for p in p_l:
        p.join()

    print('主进程',(time.time()-start))

2. 进程pid: 每一个进程在操作系统内都有一个唯一的id号,称之为pid

有两种方式可以获得进程pid

方式一:current_process 方法

from multiprocessing import Process,current_process

def task():
    print('子进程 is running... %s'%current_process().pid)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()

方式二:os 模块的getpid方法可以获得进程pid, getppid方法可以获得父进程的pid

from multiprocessing import Process
import os

def task():
    print('子进程 is running... %s'%os.getpid())
    print('子进程 is running... %s'%os.getppid())


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print('主进程..',os.getpid())   
    print('主进程..',os.getppid())

3. name方法:子进程会有默认进程名,第一个子进程默认Process-1 第二个子进程默认Process-2

from multiprocessing import Process, current_process

def task():
    print('子进程 is running...')


if __name__ == '__main__':
    p = Process(target=task, name='子进程')

    p.start()
    print(p.name)   # 子进程
    print('主进程..')

4. terminate() 和 is_alive()

terminate(): 终结进程

is_alive(): 判断进程是否存活

from multiprocessing import Process, current_process
import time

def task():
    print('子进程 is running...' )

if __name__ == '__main__':
    p = Process(target=task, name='子进程')
    p.start()
    p.terminate()  # 终结子进程
    time.sleep(0.1)   # 因为终结之后就判断了是否存活,操作系统还没来及的回收子进程,所以不睡眠就会显示存活
    print(p.is_alive()) # 判断子进程是否存活  False

    print('主进程..')

守护进程

  一:守护进程会在主进程代码执行结束后就终止

  二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

       注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

from multiprocessing import Process

import time

def task(name):
    print('%s is running..' % name)
    time.sleep(3)
    print('%s is done..' % name)

if __name__ == '__main__':
    p = Process(target=task,args=('守护进程',))
    p.daemon = True
    p.start()
    time.sleep(1)
    print('主程序 is done')

互斥锁

Lock 方法

进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,

而共享带来的是竞争,竞争带来的结果就是错乱,如何控制,就是加锁处理 

模拟抢车票:

from multiprocessing import Process, Lock
import json
import time
import random

def search(name):
    with open('db.json', 'rt', encoding='utf-8') as f:
        dic = json.load(f)
    time.sleep(1)
    print('%s 查看余票为 %s' % (name, dic['count']))

def get(name):
    with open('db.json', 'rt', encoding='utf-8') as f:
        dic = json.load(f)
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1, 3))
        with open('db.json', 'wt', encoding='utf-8') as f:
            json.dump(dic, f)
            print('%s 购票成功' % name)
    else:
        print('%s 车票已售尽' % name)

def task(name,mutex):
    search(name)
    mutex.acquire()
    get(name)
    mutex.release()

if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=task, args=('客户%s' % i,mutex))
        p.start()

僵尸进程与孤儿进程

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。详解如下

任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。这是每个子进程在结束时都要经过的阶段。如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。  如果父进程在子进程结束之前退出,则子进程将由init接管。init将会以父进程的身份对僵尸状态的子进程进行处理。

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

  孤儿进程是没有父进程的进程,孤儿进程这个重任就落到了init进程身上,init进程就好像是一个民政局,专门负责处理孤儿进程的善后工作。每当出现一个孤儿进程的时候,内核就把孤 儿进程的父进程设置为init,而init进程会循环地wait()它的已经退出的子进程。这样,当一个孤儿进程凄凉地结束了其生命周期的时候,init进程就会代表党和政府出面处理它的一切善后工作。因此孤儿进程并不会有什么危害。

以上为本次学习的内容

猜你喜欢

转载自blog.csdn.net/sql121407/article/details/82429022