python 进程之由浅入深

进程测试

python 复制代码
import os

import time
while True:
    time.sleep(0.5)
    print("hahaha")
    print("self", os.getpid()) #获取自己的进程id
    print("parent",os.getppid())  #parent 获取父进程的id

互斥锁

python 复制代码
# """
#     当多个进程共享一个数据时,可能会造成数据错乱
#     1.使用join 来让这些进程 串行   但是这将造成 无法并发  并且 进程执行任务的顺序就固定了
#     2.使用锁  将需要共享的数据加锁   其他进程在访问数据时 就必须等待当前进程使用完毕
#
#     锁的本质 就是一个bool类型的数据   在执行代码前 会先判断 这个值
#     注意 在使用锁时 必须保证锁是同一个
#
#     互斥锁
#     互相排斥的锁
#
# """
#
from multiprocessing import Process,Lock

import random
import time

def task1(lock):
    lock.acquire()  # 是一个阻塞的函数  会等到别的进程释放锁才能继续执行
    lock.acquire()
    print("1my name is:bgon")
    time.sleep(random.randint(1,2))
    print("1my age is:78")
    time.sleep(random.randint(1, 2))
    print("1my sex is:femal")
    lock.release()

def task2(lock):
    lock.acquire()
    print("2my name is:blex")
    time.sleep(random.randint(1, 2))
    print("2my age is:68")
    time.sleep(random.randint(1, 2))
    print("2my sex is:femal")
    lock.release()




def task3(lock):
    pass
# 锁的实现原理 伪代码
# l = False
# def task3(lock):
#     global l
#     if l == False:
#         l = True
#         print("3my name is:常威")
#         time.sleep(random.randint(1, 2))
#         print("3my age is:68")
#         time.sleep(random.randint(1, 2))
#         print("3my sex is:femal")
#     l = False

if __name__ == '__main__':
    lock = Lock()

    p1 = Process(target=task1,args=(lock,))
    p1.start()
    # p1.join()

    p2 = Process(target=task2,args=(lock,))
    p2.start()
    # p2.join()

    p3 = Process(target=task3,args=(lock,))
    p3.start()
    # p3.join()
#
# # 多个任务在共享一个数据时
# # 串行效率低 但是不会出问题
# # 并发效率高 但是数据可能错乱
#
#
#


# from multiprocessing import Lock,RLock,Process
#
# lock = Lock()
#
# lock.acquire()
# print("haha ")
# lock.acquire()
# print('test')
# lock.release()


# RLock 表示可重入锁 特点是 可以多次执行acquire
# Rlock 在执行多次acquire时 和普通Lock没有任何区别
# 如果在多进程中使用Rlock  并且一个进程a 执行了多次acquire
# 其他进程b要想获得这个锁 需要进程a 把锁解开 并且锁了几次就要解几次
# 普通锁如果多次执行acquire将会锁死

#
# lock = RLock()
# lock.acquire()
# lock.acquire()
# print("哈哈")
# lock.release()

# import time
# def task(i,lock):
#     lock.acquire()
#     lock.acquire()
#     print(i)
#     time.sleep(3)
#     lock.release()
#     lock.release()
# #第一个过来 睡一秒  第二个过来了 睡一秒   第一个打印1  第二个打印2
#
# if __name__ == '__main__':
#     lock = RLock()
#     p1 = Process(target=task,args=(1,lock))
#     p1.start()
#
#     p2 = Process(target=task, args=(2,lock))
#     p2.start()

开启进程的两种方式

python 复制代码
from multiprocessing import Process
import os


#
def task(name):
    print(name)
    print("self",os.getpid())#66039
    print("parent", os.getppid())#66038
    print("task run")

#  windows创建子进程时  子进程会将父进程的代码加载一遍  导致重复创建子进程
#  所以一定要将 创建子进程的代码放到main的下面
if __name__ == '__main__':
    print("self", os.getpid()) #66038
    print("parent", os.getppid()) #36520
    p = Process(target=task, name="这是子进程!",kwargs={"name":"bgon"})  # 创建一个表示进程的对象  但并不是真正的创建进程
    p.start()  # 给操作系统发送通知 要求操作系统开启进程


# 创建进程的第二种方式  继承Process  覆盖run方法
# 在子进程启动以后会自动执行run方法
# 其优势是 可以自定义 进程的属性和行为 来完成一些额外任务 例如下载
# class MyProcess(Process):
#
#     def __init__(self,url):
#         self.url = url
#         super().__init__()
#
#     # 子类中的方法  只有run会被自动执行
#     def run(self):
#         print("下载文件...." , self.url)
#         print(" run run run!")
#
#     def task(self):
#         pass
#
# def task():
#     print(123)

# if __name__ == '__main__':
#     p = MyProcess("www.baidu.com/xx.mp4")
#     p.start()

进程间内存相互独立

python 复制代码
from multiprocessing import Process

import time
a = 1000000000000

def task():
    global a
    print(id(a))
    a = 0
    print("子进程的",a)

if __name__ == '__main__':
    print(id(a))
    p = Process(target=task)
    p.start() # 给操作系统发送请求后 代码继续往下运行 至于子进程 什么时候创建 什么是执行 都跟当前进程没关系

    time.sleep(1)
    print("自己的",a)

# 子进程中的数据修改 不会影响父进程

互斥锁的使用场景_抢票

python 复制代码
import json
from multiprocessing import Process,Lock
import time
import random

"""
join和锁的区别
1.join中顺序是固定的  不公平  
2.join是完全串行  而 锁可以使部分代码串行 其他代码还是并发 

"""

# 查看剩余票数
def check_ticket(usr):
    time.sleep(random.randint(1,3))
    with open("ticket.json","r",encoding="utf-8") as f:
        dic = json.loads(f.read())
        print("%s查看 剩余票数:%s" % (usr,dic.get('count')))

def buy_ticket(usr):
    with open("ticket.json","r",encoding="utf-8") as f:
        dic = json.load(f)
        if dic.get('count')> 0:
            time.sleep(random.randint(1,3))
            dic["count"] -= 1
            with open("ticket.json", "w", encoding="utf-8") as f2:
                json.dump(dic,f2)
                print("%s 购票成功!" % usr)
        else:
            print('剩余票:',dic.get('count'))
            print('Not Found of tiket!')


def task(usr,lock):

    check_ticket(usr)
    # time.sleep(1)
    lock.acquire()
    buy_ticket(usr)
    lock.release()

if __name__ == '__main__':
    lock = Lock()

    for i in range(10):
        p = Process(target=task,args=("用户%s" % i,lock))
        p.start()
        #p.join() # 只有第一个整个必须完毕 别人才能买 这是不公平的

父进程等待子进程结束

python 复制代码
import time
from multiprocessing import Process

# def task():
#     print("上传文件....")
#     time.sleep(3)
#     print("上传结束...")
#
#
# # [进程1,进程2,进程3]
#
# if __name__ == '__main__':
#     p = Process(target=task)
#     p.start()
#
#     p.join() # 本质上  是提高了子进程优先级   当CPU在切换时 会优先切子进程
#
#     print("上传文件成功!")

def task(num):
    print("我是%s号 进程" % num)
    # time.sleep(1)
    print("=========")

if __name__ == '__main__':
    start_time = time.time()
    ps = []
    for i in range(1,4):
        p = Process(target=task,args=(i,))
        p.start()
        print("----{}".format(i))
        # ps.append(p)

    for p in ps:
        p.join()

    print(time.time()-start_time)
    print("over")

process 常用属性

python 复制代码
from multiprocessing import Process

import time


def task():
    # time.sleep(3)
    print("执行完毕!")


if __name__ == '__main__':
    p = Process(target=task, name="alex")
    p.start()
    print(p.name)
    #
    # # time.sleep(1)
    # print(p.is_alive())
    # #
    p.terminate()
    # #
    print(p.is_alive())
    # # print(p.pid)
    # p.terminate()  # 终止这个进程
    # print(p.pid)
    # print(p.is_alive())
    # p.daemon  # 守护进程

死锁

python 复制代码
"""



    死锁 指的是 锁 无法打开了   导致程序死卡

    首先要明确  一把锁 时不会锁死的

    正常开发时 一把锁足够使用 不要开多把锁


"""

from multiprocessing import Process,Lock
import time
def task1(l1,l2,i):
    l1.acquire()
    print("盘子被%s抢走了" % i)
    time.sleep(1)


    l2.acquire()
    print("筷子被%s抢走了" % i)
    print("吃饭..")
    l1.release()
    l2.release()


    pass

def task2(l1,l2,i):

    l2.acquire()
    print("筷子被%s抢走了" % i)

    l1.acquire()
    print("盘子被%s抢走了" % i)

    print("吃饭..")
    l1.release()
    l2.release()


if __name__ == '__main__':
    l1 = Lock()
    l2 = Lock()
    Process(target=task1,args=(l1,l2,1)).start()
    Process(target=task2,args=(l1,l2,2)).start()

IPC 进程间通讯

python 复制代码
"""
    IPC  进程间通讯
    由于进程之间内存是相互独立的 所以需要对应积极而方案 能够使得进程之间可以相互传递数据

    1.使用共享文件,多个进程同时读写同一个文件
        IO速度慢,传输数据大小不受限制

    2.管道 是基于内存的,速度快,但是是单向的 用起来麻烦(了解)


    3.申请共享内存空间,多个进程可以共享这个内存区域(重点)
        速度快但是 数据量不能太大
"""

from multiprocessing import Manager,Process
#
# def task(m):
#
#     print(m["num"])
#
# if __name__ == '__main__':
#     # 开启了一个Manager
#     with Manager() as m:
#         m["num"] = 100 # 在这个空间中存储了一个num
#
#         for i in range(20):
#             p = Process(target=task,args=(m,))
#             p.start()
#
#

from multiprocessing import Manager,Process,Lock
def work(d):
    # with lock:
        d['count']-=1

if __name__ == '__main__':

    with Manager() as m:
        dic=m.dict({'count':100}) #创建一个共享的字典
        p_l=[]
        for i in range(100):
            p=Process(target=work,args=(dic,))
            p_l.append(p)
            p.start()

        for p in p_l:
            p.join()
        print(dic)

僵尸进程

python 复制代码
import  time
from multiprocessing import  Process
def task1():
    print("子进程 run")

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

    time.sleep(100000)

队列

python 复制代码
"""
    队列   不只用于进程间通讯
    也是一种常见的数据容器

    其特点是:先进先出
    其优点是:可以保证数据不会错乱 即使在多进程下  因为其put和get默认都是阻塞的


    对比堆栈刚好相反 :后进先出
    #

"""

from multiprocessing import Queue

# q = Queue(1)  # 创建一个队列 最多可以存一个数据
#
# q.put("张三")
# print(q.get())
#
# q.put("李四") # put默认会阻塞 当容器中已经装满了
#
# print(q.get())
# print(q.get()) # get默认会阻塞 当容器中已经没有数据了
#
# print("over")


q = Queue(1)  # 创建一个队列 最多可以存一个数据
#
q.put("张三")
# q.put("李四",False) # 第二个参数 设置为False表示不会阻塞 无论容器是满了 都会强行塞 如果满了就抛异常

print(q.get())
print(q.get(timeout=3)) # timeout 仅用于阻塞时

# q.put("李四") # put默认会阻塞 当容器中已经装满了
#
# print(q.get())
# print(q.get()) # get默认会阻塞 当容器中已经没有数据了
#
# print("over")

生产者消费者模型

python 复制代码
"""
    什么是生产者 消费者 模型
    生产者 产生数据的一方
    消费者 处理数据的一方


    例如需要做一个爬虫
    1.爬取数据
    2.解析数据

    爬去和解析都是耗时操作,如果正常按照顺序来编写代码,将造成解析需要等待爬去  爬去取也需要等待解析
    这样效率是很低的
    要提高效率 就是一个原则 让生产者和消费解开耦合 自己干自己的
    如何实现:
        1.将两个任务分别分配给不同进程
        2.提供一个进程共享的数据容器



"""
import random
from multiprocessing import Process,Queue
import time
# 爬数据
def get_data(q):

    for num in range(5):
        print("正在爬取第%s个数据" % num)
        time.sleep(random.randint(1,2))
        print("第%s个数据 爬取完成" % num)
        # 把数据装到队列中
        q.put("第%s个数据" % num)


def parse_data(q):
    for num in range(5):
        # 取出数据
        data = q.get()
        print("正在解析%s" % data)
        time.sleep(random.randint(1, 2))
        print("%s 解析完成" % data)

if __name__ == '__main__':
    # 共享数据容器
    q = Queue(5)
    #生产者进程
    produce =  Process(target=get_data,args=(q,))
    produce.start()
    #消费者进程
    customer = Process(target=parse_data,args=(q,))
    customer.start()

总结

python 复制代码
1. 并发编程
    让你的程序可以同时处理多个任务

2.并发的基石是 多道技术
    空间复用: 同一时间 内存存储了多个应用程序
             不同应用程序之间的内存是相互独立的
    时间复用: 当一个程序遇到了IO操作时 会切换到其他应用程序  ,以此来提高CPU的利用率

    多道技术的缺点: 当应用程序都是计算任务时 切换反而降低效率 (但是必须得切 才能保证多任务并发)


3.并发 与 并行
    并发 多个事件 同时发生, 也称之为伪并行
    并行 多个事件 同时进行,

    阻塞和非阻塞 指的是程序的状态
    就绪  运行  阻塞


4.两种使用进程的方式
    1.直接创建Process对象 指定target参数
    2.继承Process 覆盖run方法

5.join函数
    提高优先级 使 父进程等待子进程结束


6.孤儿进程与僵尸进程路径了解

    孤儿进程 是指 父进程已经终止了  但是自己还在运行  是无害的
    孤儿进程会自定过继给操作系统


    僵尸进程  是指 子进程执行完成所有任务 已经终止了但是 还残留一些信息(进程id 进程名)
    但是父进程 没有去处理这些残留信息 导致残留信息占用系统内存
    僵尸进程时有害的

    当出现大量的僵尸进程时 会占用系统资源 可以把它父进程杀掉  僵尸就成了孤儿 操作系统会负责回收数据
相关推荐
西柚与蓝莓1 小时前
【开源开放体系总结】
python
belldeep4 小时前
python:reportlab 将多个图片合并成一个PDF文件
python·pdf·reportlab
FreakStudio7 小时前
全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用
python·单片机·嵌入式·面向对象·电子diy
丶21367 小时前
【CUDA】【PyTorch】安装 PyTorch 与 CUDA 11.7 的详细步骤
人工智能·pytorch·python
_.Switch8 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一个闪现必杀技8 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
小鹿( ﹡ˆoˆ﹡ )9 小时前
探索IP协议的神秘面纱:Python中的网络通信
python·tcp/ip·php
卷心菜小温9 小时前
【BUG】P-tuningv2微调ChatGLM2-6B时所踩的坑
python·深度学习·语言模型·nlp·bug
陈苏同学9 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
唐家小妹9 小时前
介绍一款开源的 Modern GUI PySide6 / PyQt6的使用
python·pyqt