互斥锁 守护进程 join方法 创建进程

概要

  • 代码创建过程

  • join方法

  • 进程间数据默契隔离

  • 进程对象相关属性和方法

  • 僵尸进程与孤儿进程

  • 守护进程

  • 互斥锁

内容

1、代码创建进程

创建进程的方法有哪些?

1.鼠标双击桌面一个应用图标

2.代码创建

创建进程的本质:在内存中申请一块内存空间用于运行相应的程序代码

第一种创建进程的方式

from muitiprocessing import Process
import time
    print('%s is running'% name)
    time.sleep(3)
    print('%s is over'% name)
    
if __name__=='__main__':
    p = Process(target = task,args = ('jason',))  # 创建一个进程对象
    p.start()  # 告诉操作系统创建一个新的进程
    print('主进程')
    
# 强调:不同的操作系统创建进程的要求不一样
       在windows中创建进程是导入模块的方式进行 所以创建进程的代码必须写在__main__子代码中
        否则计算机会直接保错 因为计算机会在内存中无限制创建过程
        在linux和mac中创建进程是直接拷贝一份源代码然后执行 不需要写在__main__子代码中    

第二种创建方式:通过继承的方式

from multiprocessing import Process
import time
class MyProcess(Process):
    def __init__(self,username):
        self.username = username
        super().__init__()
    def run(self):
        print('您好啊 小姐姐',self.username)
        time.sleep(3)
        print('get out!!!',self.username)
if __name__ == '__main__':
    p = MyProcess('tony')
    p.start()
    print('主进程')
        

2、进程实现并发

思路:只要在服务端将于客户端通信的代码封装成一个函数 之后每加一个新的客户端就会创建一个进程专门做交互

服务端
import socket
server = socket.socket()
server.bind('127.0.0.1',8080)
server.listen(5)

def talk(sock):
        while True:
          data = sock.recv(1024)
          print(data.decode('utf8'))
          sock.send(data.upper())

if __name__ == '__main__':
    server = get_serve()
    while True:
        sock, addr = server.accept()
        p = Process(target=talk, args=(sock, ))
        p.start()
       
客户端
import socket

client = socket.socket()
client.connect(('127.0.0.1', 8080))

while True:
    client.send(b'hello big baby~')
    data = client.recv(1024)
    print(data.decode('utf8'))


3.join方法:等待子进程代码执行完毕后主进程再执行

1.join方法的简单使用
2.如何真正理解等待的过程
from multiprocessing import Process
import time

def task(name,n):
    print(f'{name} is running')
    time.sleep(n)
    print(f'{name} is over')
    
if __name__ == '__main__':
    p1 = Process(target=task,args='jason',1))
    p2 = Process(target=task,args='kevin',2))
     p3 = Process(target=task,args='tony',3))
     start_time = time.time()
     p1.start()
     p2.start()
     p3.start()
     p1.join()
     p2.join()
     p3.join()
     end_time = time.time()- start_time()
     print('主进程'f'总耗时:{end_time}')  # 主进程 总耗时:3.015652894973755  三个start同时开始 所以是异步进行
    需要注意的是:如果是一个start一个join交替执行 那么总耗时就是各个任务耗时总和 同步执行
        
  """
  需求:想让p.start()之后的代码 等待子进程全部运行结束之后再打印出来
  	1.小白思路:直接time.sleep()  只要下面的睡眠等待时间比上面那个睡眠时间长就可以达到目的 确实是可行的 但是在很多实践过程中我们不知道上面那个具体的睡眠等待时间到底是多少 所以不可取 因为子进程运行的时间是不可控的
  	2.join方法
  	  针对多个子进程的等待 一起写多个start 然后在写多个join
  	"""

4、进程间数据默认隔离:内存可以看成是有很多小间隔组成的 彼此互不干扰

from multiprocessing import Process

money = 999
def task():
    global money  如果局部空间想改全部名称空间内的数据时需要加global声明
    money = 666
    
if __name__ == '__main__':
    p = Process(target = task)
    p.start()
    p.join()  # 确保子进程代码运行结束再打印money
    print(money)
    
"""默认隔离 但是可以通过一些技术打破 

5、进程对象属性和方法

进程号如何查看:
window:tasklist结果集中PID
mac: ps-ef
1.查看进程号的方法
1.1 current_process函数
from multiprocessing import Process,current_process
current_process().pid

# 获取进程号的用处之一就是可以通过代码的方式管理进程
windows   taskkill关键字
mac/linux kill 关键字
1.2 os模块
os.getpid()  # 获取当前进程的进程号
os.getppid()  # 获取当前进程的父进程号

2.杀死子进程
terminate()
3.判断子进程是否存活
is_alive()

6、僵尸进程与孤儿进程

僵尸进程
# 为什么主要进程默认需要等待子进程结束之后才会结束?
所有的子进程在运行结束之后都会变成僵尸进程(可以理解为死了没有死透)
还保留着pid和一些运行过程中的记录便于主进程进行查看(短时间内保存)
这些信息会被主动进程回收(回收后僵尸彻底死了)
1.主进程正常结束
2.调用join方法结束

孤儿进程
# 子进程存活着 父进程意外死亡
子进程会被操作系统自动接管

7、守护进程

守护即是死活全部参考守护的对象
守护对象死立刻死

from multiprocessing import Process
import time

def talk(name):
    print(f'{name}活的')
    time.sleep(3)
    print(f'{name}死的')
    
if __name__ == '__main__':
    p = Process(target = task,args = ('name',))
    # 必须写在start前面
    p.daemon = True  # 将子进程设置为守护进程:主进程结束 子进程立刻结束
    p.start()
    print('我已寿终正寝') 

8、互斥锁

场景:每逢节假日抢票时:
        手机上明明显示还有余票 但是点击购买时候确是显示已经没有票了
        之后回到查询页面时发现确实显示没有票了
        
比如上午10点打开买票软件查看票数 系统给你发过来的是10点对应的数据

# 代码模拟抢票(是有问题的)
import json
from muitiprocessing import Process
import time
import random

# 查票
def search(name):
    with open(r'ticket_data.jsom','r',encoding ='utf8') as f:
        data = json.load(f)
        print(f'{name}查询当前余票:%s'%data.get('ticket_num'))
        
# 买票
def buy(name):
    """
    点击买票是需要再次检查票的 因为期间其他人肯可能已经将票买走了"""
    # 1.查票
    with open(r'ticket_data.json','r',encoding = 'utf8') as f:
    data = json.load(f)
    time.sleep(random.randint(1,3))
    # 2.判断是否还有余票
 	if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'ticket_data.json','w',encoding = 'utf8') as f:
            json.dump(data,f)
        print(f'{name}抢票成功')
    else:
        print(f'{name}抢票失败 没有余票了')
并发的情况下操作同一份数据 极有可能造成数据错乱的问题
这个时候统一都会采用互斥锁的策略来解决(无论是基础阶段还是后期)

为什么要有互斥锁?
互斥锁:将并发变成串行 牺牲了效率但是保证了数据的安全
以后正常编程很少会出现让我们自己编写代码操作锁的情况!!!

互斥锁如何使用?
mutex = Lock()
mutex.acquire()  # 抢锁
mutex.release()  # 放锁

posted @   一颗平凡的小石头  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
点击右上角即可分享
微信分享提示