创建进程的多种方式、join方法、进程对象相关操作、进程间数据默认隔离、生产者与消费者模型

创建进程的多种方式

1.双击桌面程序图标

2.1代码创建进程

创建进程的代码在不同的操作系统中,底层原理有区别:在windows中, 创建进程类似于导入模块,需要启动脚本(if name == 'main'😃,没有启动脚本,就相当于进入了死循环;在mac、linux中,创建进程类似于直接拷贝,不需要启动脚本,但是为了兼容性,也可以使用

from multiprocessing import Process
import time
def task(name):
    print(f"{name}在子进程中运行开始")
    time.sleep(2)
    print(f"{name}在子进程中运行结束")

if __name__ == '__main__':
    p = Process(target=task,args=('nana',))
    p.start()
    print("进程")
结果:
    进程
    nana在子进程中运行开始
    nana在子进程中运行结束

知识补充:
1.p = Process(target=task,args=('nana',)) 创建一个进程对象,其中args就是通过元组的形式给函数传参,也可以是通过kwargs={'name':'nana'}
2.p.start() 相当于告诉操作系统创建一个进程(异步操作),普通的函数调用是同步操作

2.2 代码创建进程

from multiprocessing import Process
import time

class My_Process(Process):
    def __init__(self,name):
        super(My_Process, self).__init__()
        self.name = name
    def run(self):
        print(f"{self.name}在子进程中运行开始")
        time.sleep(2)
        print(f"{self.name}在子进程中运行结束")

if __name__ == '__main__':
    obj =   My_Process('nana')
    obj.start()
    print("主进程")

结果:
    主进程
    nana在子进程中运行开始
    nana在子进程中运行结束

join()方法

join()方法的作用是使主进程等待子进程运行结束之后再运行

需求:让子进程执行完了再执行主进程

方式一、在主进程代码中添加time.sleep()

在主进程代码中添加time.sleep()的这个方法不合理,原因是无法准确把握子进程执行的时间

from multiprocessing import Process
import time

def task(name):
    print(f"{name}在子进程中运行开始")
    time.sleep(2)
    print(f"{name}在子进程中运行结束")


if __name__ == '__main__':
    p = Process(target=task,args=('nana',))
    p.start()
    time.sleep(3)
    print("进程")

结果:
    nana在子进程中运行开始
    nana在子进程中运行结束
    进程

方式二、join()方法

from multiprocessing import Process
import time

def task(name):
    print(f"{name}在子进程中运行开始")
    time.sleep(2)
    print(f"{name}在子进程中运行结束")


if __name__ == '__main__':
    p = Process(target=task,args=('nana',))
    p.start()
    p.join()
    print("进程")

结果:
    nana在子进程中运行开始
    nana在子进程中运行结束
    进程

join()方法进阶练习

需求:计算下列程序运行的时间

from multiprocessing import Process
import time

def task(name,n):
    print(f"{name}在子进程中运行开始")
    time.sleep(n)
    print(f"{name}在子进程中运行结束")


if __name__ == '__main__':
    p1= Process(target=task,args=('nana',1))
    p2= Process(target=task, args=('jason', 2))
    p3 = Process(target=task, args=('kevin', 3))
    start_time = time.time()
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    p3.start()
    p3.join()
    end_time = time.time()
    print('总耗时:%s'%(end_time-start_time))
    print("主进程")
    print("进程")

结果:
    nana在子进程中运行开始
    nana在子进程中运行结束
    jason在子进程中运行开始
    jason在子进程中运行结束
    kevin在子进程中运行开始
    kevin在子进程中运行结束
    总耗时:6.896258115768433
    主进程
    进程
from multiprocessing import Process
import time

def task(name,n):
    print(f"{name}在子进程中运行开始")
    time.sleep(n)
    print(f"{name}在子进程中运行结束")


if __name__ == '__main__':
    p1= Process(target=task,args=('nana',1))
    p2= Process(target=task, args=('jason', 2))
    p3 = Process(target=task, args=('kevin', 3))
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time()
    print('总耗时:%s'%(end_time-start_time))
    print("主进程")
    print("进程")

结果:
    nana在子进程中运行开始
    jason在子进程中运行开始
    kevin在子进程中运行开始
    nana在子进程中运行结束
    jason在子进程中运行结束
    kevin在子进程中运行结束
    总耗时:3.4667296409606934
    主进程
    进程

进程间数据默认隔离

多个进程数据彼此之间默认是相互隔离的,如果真的想交互,需要借助于'管道'或者'队列'

from multiprocessing import Process

money = 100

def task():
    global money
    money = 666
    print('子进程中的Money:',money)

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('主进程中的money:',money)

结果:
    子进程中的Money: 666
    主进程中的money: 100

知识补充:Queue模块

队列:先进先出

1.创建队列对象

q = Queue(),括号内填写指定队列可以容纳的数据个数,默认是:2147483647

from multiprocessing import Queue
q = Queue(3)

2.往队列添加数据

obj.put() 如果超出数据存放极限,那么程序一直处于阻塞态,直到队列中有数据被取出

q.put(1)
q.put(2)
q.put(3)
q.put(4) # 超出了数据存放极限

3.从队列中取数据

obj.get() 如果超出数据获取极限,那么程序一直处于阻塞态,直到队列中有数据被添加;obj.get_nowait() 如果队列中没有数据可取,直接报错

print(q.get()) # 1
print(q.get()) # 2
print(q.get()) # 3
print(q.get()) # 超出数据获取极限

print(q.get_nowait()) # 1
print(q.get_nowait()) # 2
print(q.get_nowait()) # 3
print(q.get_nowait()) # 报错

4.判断队列是否已经存满

obj.full()

q = Queue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.full())  # True

5.判断队列是否为空

obj.empty()

print(q.get())
print(q.get())
print(q.get())
print(q.empty())  # True

注意:obj.full()、obj.empty()、obj.get_nowait()方法在多进程下不能准确使用

进程间通信(IPC机制)

想要进程间通信,就需要借助于'管道'或者'队列'

主进程与子进程通信

from multiprocessing import Queue,Process

def task1(q):
    print("子进程从队列里获取了数据:",q.get())

if __name__ == '__main__':
    q = Queue()
    q.put('主进程向队列里放了数据')
    p1 = Process(target=task1,args=(q,))
    p1.start()
    p1.join()
    print("主进程")
    
结果:
    子进程从队列里获取了数据: 主进程向队列里放了数据
    主进程

子进程与子进程通信

from multiprocessing import Queue,Process

def task1(q):
    q.put('子进程task1往队列里添加了数据')

def task2(q):
    print("子进程task2从队列里获取了数据:",q.get())

if __name__ == '__main__':
    q = Queue()  # 在主进程中产生q对象 确保所有的子进程使用的是相同的q
    p1 = Process(target=task1,args=(q,))
    p2 = Process(target=task2, args=(q,))
    p1.start()
    p1.join()
    p2.start()
    p2.join()
    print("主进程")
结果:
    子进程task2从队列里获取了数据: 子进程task1往队列里添加了数据
    主进程

生产者消费者模型

生产者指产生数据,消费者指处理数据;完整的生产者消费者模型至少有三个部分:生产者、消息队列/数据库、消费者

image

进程相关方法

1.查看进程号

获取当前进程进程号:os.getpid()、current_process().pid;获取产生当前进程的父进程号:os.getppid()

from multiprocessing import Process,current_process
import os

def task():
    print('子进程',os.getpid())
    print('父进程',os.getppid())
    print('子进程',current_process().pid)

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('父进程',os.getpid())
    print('父进程',current_process().pid)
    print("进程")
    
结果:
    子进程 11204
    父进程 18660
    子进程 11204
    父进程 18660
    父进程 18660
    进程

2.销毁子进程

obj.terminate()

from multiprocessing import Process
import time

def task(name):
    print(f"{name}在子进程中运行开始")
    time.sleep(2)
    print(f"{name}在子进程中运行结束")

if __name__ == '__main__':
    p = Process(target=task,args=('nana',))
    p.start()
    p.terminate()

3.判断进程是否存活

obj.is_alive()

from multiprocessing import Process
import time

def task(name):
    print(f"{name}在子进程中运行开始")
    time.sleep(2)
    print(f"{name}在子进程中运行结束")


if __name__ == '__main__':
    p = Process(target=task,args=('nana',))
    p.start()
    p.terminate()
    time.sleep(0.1)
    print(p.is_alive())  # False

守护进程

守护进程会随着主进程的结束而结束

用obj.daemon = True,将子进程设置为守护进程(当主进程代码结束,子进程立刻结束),需要注意的是obj.daemon = True要写在obj.start()前面

from multiprocessing import Process
import time

def task(name):
    print(f"{name}在子进程中运行开始")
    time.sleep(2)
    print(f"{name}在子进程中运行结束")

if __name__ == '__main__':
    p = Process(target=task,args=('nana',))
    p.daemon = True
    p.start()
    print("主进程")
    
结果:
	主进程

僵尸进程与孤儿进程

1.僵尸进程:子进程运行结束(僵尸),但是由子进程产生产生的相关资源没有完全清空,需要父进程参与回收
2.孤儿进程:父进程意外结束,子进程正常运行,该子进程就称之为孤儿进程。此时孤儿进程产生的相关资源,会被操作系统回收清理

模拟抢票系统--粗略版

from multiprocessing import Process
import json
import time
import random

def select_ticket(name):
    with open(r'ticket.json','r',encoding='utf8')as f :
        data = json.load(f)
    print(name,f"余票:{data.get('ticket')}")


def buy_ticket(name):
    time.sleep(random.randint(1,3))
    with open(r'ticket.json', 'r', encoding='utf8')as f:
        data = json.load(f)
    if data.get('ticket') > 0:
        data['ticket'] -= 1
        print(name,"购买成功")
    else:
        print("没票了")
    with open(r'ticket.json', 'w', encoding='utf8')as f:
        json.dump(data,f)

def run(name):
    select_ticket(name)
    buy_ticket(name)

if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run,args=(i,))
        p.start()

posted @ 2022-08-09 19:07  DRAMA-娜娜  阅读(45)  评论(0编辑  收藏  举报