Welcome!!!

F

伞兵一号,申请出战

并发编程(二)

并发编程(二)

代码创建进程

"""
创建进程的方式有哪些
	1.鼠标双击桌面一个应用图标
	2.代码创建
	
创建进程的本质:在内存中申请一块内存空间用于运行相应的程序代码
"""
# 代码创建进程有两种方式
# 1.函数创建进程
    from multiprocessing import Process

    def my_print(data):
        print('输出:'+data)
        print('输出进程结束')

    if __name__ == '__main__':  # windows电脑需要加main判断,因为windows是以导入模块的形式创建的
        p = Process(target=my_print,args=('我是输出函数',))  # 创建一个进程对象,绑定函数,参数
        p.start()  # 启动这个进程
        print('主进程结束')
    输出结果:
        主进程结束
        输出:我是输出函数
        输出进程结束
        
# 2.类创建进程
	from multiprocessing import Process
    
	class MyProcess(Process):  # 定义自己的进程类
        def __init__(self,data):  # 重写__init__方法传参
            self.data = data
            super().__init__()

        def run(self):  # 需要另外开辟进程的方法
            print('输出:'+self.data)
            print('输出进程结束')

    if __name__ == '__main__':
        p = MyProcess('我是输出函数')
        p.start()
        print('主进程结束')
    输出结果:
        主进程结束
        输出:我是输出函数
        输出进程结束

进程实现并发

# 思路:每来一个连接我就开辟一个进程专门处理和这个连接的交互
# 代码示例
# 服务端代码
    import socket
    from multiprocessing import Process

    def get_server():
        server = socket.socket()
        server.bind(('127.0.0.1', 8080))
        server.listen(5)
        return server


    # 把通信代码封装成函数
    def reply(sock):
        while True:
            data = sock.recv(1024)
            print(data.decode('utf8'))
            sock.send(data.upper())


    # 每来一个连接创建一个进程处理
    def main():
        server = get_server()
        while True:
            sock, addr = server.accept()
            if __name__ == '__main__':
                p = Process(target=reply, args=(sock,))
                p.start()

    if __name__ == '__main__':
        main()
        
# 客户端代码
	import socket

    client = socket.socket()
    client.connect(('127.0.0.1',8080))
    while True:
        client.send('hello world'.encode('utf8'))
        data = client.recv(1024)
        print(data.decode('utf8'))
     '''定义多个客户端,代码大致相同'''
    
'''
ps:windows系统需要将获取socket连接对象的代码封装成函数,否则会直接报错'OSError: [WinError 10048]  通常每个套接字地址(协议/网络地址/端口)只允许使用一次'
'''

join方法

# 作用
	让主进程等待子进程结束再执行
eg:
    from multiprocessing import Process

    def my_print(data):
        print('输出:'+data)
        print('输出进程结束')

    if __name__ == '__main__':  # windows电脑需要加main判断,因为windows是以导入模块的形式创建的
        p = Process(target=my_print,args=('我是输出函数',))  # 创建一个进程对象,绑定函数,参数
        p.start()  # 启动这个进程
        p.join()
        print('主进程结束')
    输出结果:
        输出:我是输出函数
        输出进程结束
        主进程结束

进程间数据默认隔离

from multiprocessing import Process

data = 999

def update():
    global data  # 声明修改全局名称空间变量data
    data = 888

if __name__ == '__main__':
    p = Process(target=update)
    p.start()
    print(data)  # 输出主进程的data  # 999

update()
print(data)  # 888

'''
上述代码,子进程调用了修改全局变量的函数,但是主进程中的变量data并没有被修改,我们在主进程中调用修改方法,再输出则修改了

不同的进程间存在着数据默认隔离,即当前进程默认不能修改其他进程的数据

可以通过一些手段打破这个限制:队列
'''

进程对象属性和方法

"""
进程号如何查看
	windows: 			tasklist结果集中PID
	mac:					ps -ef
通过端口号查看进程号
	windows				netstat -ano|findstr 端口号
	mac					sudo lsof -i tcp:端口号
杀进程
	windows				taskkill -f -pid 进程号
	mac					sudo kill 进程号
"""
# 代码实现
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()

僵尸进程与孤儿进程

僵尸进程
	所有的子进程在运行结束后都会变成僵尸进程(没死透)
    还保留着pid和一些运行过程的中的记录便于主进程查看(短时间保存)
    这些信息会被主进程回收(死透了)
    回收时间:
        1.主进程正常结束
        2.调用join方法(所以调用join方法,主进程在子进程结束后结束,原理就是阻塞程序,回收掉子进程的信息才会继续执行下去)
    
孤儿进程
	子进程存活,父进程意外死亡
    这时子进程会被操作系统自动接管(儿童福利院)

守护进程

'''
守护即死活全部参考守护的对象
	守护的对象死了立即死亡
'''
关键参数:'daemon'
    import time
from multiprocessing import Process

def son():
    print('我是守护进程')
    time.sleep(3)
    print('我守护3秒了')

if __name__ == '__main__':
    p = Process(target=son)
    p.daemon = True  # 必须加在start前面,或者写在实例化类括号里
    p.start()
    print('主进程结束了')
不加p.daemon = True输出结果:
    主进程结束了
加了p.daemon = True输出结果:
    主进程结束了
    我是守护进程
    我守护3秒了

互斥锁(重要)

##########################################
当多个进程操作同一份数据的时候会造成数据的错乱!!!
这个时候需要加锁处理(互斥锁)
	将并发变成串行 牺牲了效率但是保证的数据的安全
 
互斥锁并不能轻易使用 容易造成死锁现象
互斥锁只在处理数据的部分加锁 不能什么地方都加 严重影响程序的效率
##########################################
from multiprocessing import Process, Lock
mutex = Lock()
mutex.acquire()  # 抢锁
mutex.release()  # 放锁
ps:我们以后在编程生涯中几乎不会自己操作锁 理解原理即可
# 示例代码:
	# 模拟抢票功能
    import json


    import time
    from multiprocessing import Process, Lock

    # 查询余票
    def search(name):
        with open(r'ticket_data_json', 'r', encoding='utf8') as f:
            data = json.load(f)
        return data

    # 买票
    def buy(name,mutex):
        data = search(name)
        print(f'{name}查询当前余票:%s' % data.get('ticket'))
        if data.get('ticket') != 0:
            mutex.acquire()  # 抢锁
            # 先锁定一张票
            with open(r'ticket_data_json', 'w', encoding='utf8') as f:
                data['ticket'] -= 1
                json.dump(data,f)
            choice = 'y'
            if choice == 'y':
                print(f'{name}购票成功')
                mutex.release()  # 放锁
            elif choice == 'n':
                # 用户没买,把票放回去
                with open(r'ticket_data_json', 'w', encoding='utf8') as f:
                    data['ticket'] += 1
                    json.dump(data, f)
                    print(f'{name}取消购买')
        else:
            print('没票了')

    def run(name,mutex):
        search(name)
        buy(name,mutex)

    if __name__ == '__main__':
        for i in range(10):
            mutex = Lock()
            p = Process(target=run,args=(f'用户{i}',mutex))
            p.start()
            
"""
锁相关知识
	行锁:针对行数据加锁 同一时间只能一个人操作
	表锁:针对表数据加锁 同一时间只能一个人操作
锁的应用范围很广 但是核心都是为了保证数据的安全!!!
"""

posted @   程序猿伞兵一号  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示