Python从0到100(二十五):Python进程、多进程、线程以及同步和死锁

一 传统编程的缺陷

传统编程的弊端:

py 复制代码
# 必须按照顺序执行,多个任务无法同时在还行
import time


def sing():
    for i in range(5):
        print("sing: hero")
        time.sleep(1)       # 每唱一次,等1秒再唱


def dance():
    for i in range(5):
        print("dance: swan")
        time.sleep(1)       # 每唱一次,等1秒再跳


def main():
    sing()
    dance()


if __name__ == "__main__":
    main()

2个任务花费的时间是10秒,如果要边跳边唱,其实2个任务是可以在最长的那个任务完成时全部完成的。

实现多任务编程的方式有很多,如:多进程、多线程、协程等。

二 使用多进程方式实现多任务

py 复制代码
# 必须按照顺序执行,多个任务无法同时在还行
import time
import multiprocessing


def sing():
    for i in range(5):
        print("sing: hero")
        time.sleep(1)       # 每唱一次,等1秒再唱


def dance():
    for i in range(5):
        print("dance: swan")
        time.sleep(1)       # 每唱一次,等1秒再跳


def main():
    p1 = multiprocessing.Process(target=sing)
    p2 = multiprocessing.Process(target=dance)
    p1.start()
    p2.start()


if __name__ == "__main__":
    main()

三 进程的一些操作

通过 htop 命令可以查看详细的进程列表。

注意:使用kill -9 pid 杀死主进程后,子进程不会被杀死,此时命令行也会无法正常退出,因为该命令的信号是发给了主进程来执行杀死任务,子进程由于没有父进程,变成了孤儿进程,之后被init进程领养。也就是说杀死主进程后,子进程的父进程称为了init进程。

通过 os.getpid() 可以获取到当前进程的pid,os.getppid()可以获取父进程id。

四 进程间通信

进程之间无法直接进行通信,因为他们是互相独立的应用程序。

进程之间要实现通信,常见的方式有:socket等,python中可以使用队列方式实现:

py 复制代码
queue = multiprocessing.Queue(3)
queue.put("111")
queue.put(222)

# 取数据
res = queue.get()
print(res)
# 判断: q.full()  q.empty()

五 进程池

py 复制代码
p = multiprocessing.Pool(3)

六 多线程方式实现多任务

py 复制代码
import time
import threading


def sing():
    for i in range(5):
        print("sing: hero")
        time.sleep(1)       # 每唱一次,等1秒再唱


def dance():
    for i in range(5):
        print("dance: swan")
        time.sleep(1)       # 每唱一次,等1秒再跳


def main():
    t1 = threading.Thread(target=sing)      # 创建一个线程对象
    t2 = threading.Thread(target=dance)     # 创建一个线程对象
    t1.start()                              # 开启线程
    t2.start()                              # 开启线程


if __name__ == "__main__":
    main()

七 线程相关API

通过 threading.Thread() 可以创建线程,threading.enumerate() 也可以查看当前所有的线程:

py 复制代码
import time
import threading


def sing():
    for i in range(5):
        print("sing: hero")
        time.sleep(1)       # 每唱一次,等1秒再唱


def dance():
    for i in range(5):
        print("dance: swan")
        time.sleep(1)       # 每唱一次,等1秒再跳


def main():

    t1 = threading.Thread(target=sing)
    t2 = threading.Thread(target=dance)

    t1.start()
    t2.start()

    while True:
        length = len(threading.enumerate())
        print("当前线程数为:%d" % length)
        if length <= 1:
            break
        time.sleep(0.5)


if __name__ == "__main__":
    main()

八 同步与死锁

线程是共享全局变量的,这样就会造成数据的混乱:

py 复制代码
import time
import threading

# 定义共享的全局变量
num = 0


def add100():
    global num
    for i in range(100000):
        num = num + 0.00001


def add1000():
    global num
    for i in range(100000):
        num = num + 1000


def main():

    t1 = threading.Thread(target=add100)
    t2 = threading.Thread(target=add1000)

    t1.start()
    t2.start()

    time.sleep(5)
    print(num)              # 每次输出的结果是不相同的


if __name__ == "__main__":
    main()

使用互斥锁实现同步的方案:

py 复制代码
import time
import threading

# 定义共享的全局变量
num = 0


def add100():
    global num
    mutex.acquire()     # 加锁:若已经加锁,则会直到锁被揭开
    for i in range(100000):
        num = num + 0.00001
    mutex.release()     # 解锁


def add1000():
    global num
    mutex.acquire()     # 加锁:若已经加锁,则会直到锁被揭开
    for i in range(100000):
        num = num + 1000
    mutex.release()     # 解锁


# 创建互斥锁,默认不会上锁
mutex = threading.Lock()


def main():

    t1 = threading.Thread(target=add100)
    t2 = threading.Thread(target=add1000)

    t1.start()
    t2.start()

    time.sleep(5)
    print(num)          # 100000001.0 永远不会变


if __name__ == "__main__":
    main()
相关推荐
一只爱撸猫的程序猿6 分钟前
全球出货第二,却不在 AI 的默认推荐里:一份悖论解剖报告
人工智能·python·产品
高洁0112 分钟前
大模型检索增强生成(RAG)的技术原理与架构设计
人工智能·深度学习·机器学习·django·迁移学习
数聚天成DeepSData14 分钟前
两份名录里的同名机构,主键该怎么合并
人工智能·深度学习·机器学习·数据集·deepsdata
海宇数据16 分钟前
零信任架构实战:基于海宇双人婚姻评估查询构建自动化配偶签约一致性审查网关
人工智能·ai·工具分享
悟天特斯17 分钟前
安防一体化:从“各管各的“到“全局联动“
java·大数据·网络·人工智能·物联网
pjj1985421 分钟前
YOLO 目标检测算法系列梳理:从 V1 到 V5 的原理演进
算法·yolo·目标检测
l1t22 分钟前
DeepSeek总结的AI 智能体应该用哪种语言搜索其记忆:SQL 还是 SPARQL?
数据库·人工智能·sql
霸道流氓气质30 分钟前
AI 翻译插件:翻译记忆级联复用、术语混合检索与结构化质量门禁的 Vue3 + Spring AI 生产级实战
java·人工智能·spring
克莱斯勒ya33 分钟前
机器人官网及机器人相关设计学习视频下载
人工智能
yangmu320340 分钟前
把 AI 智能体接入 PLC 程序:从“能跑”到“敢用”的实战教程
人工智能