• python线程和进程


    版权声明

    • 本博客的内容基于我个人学习黑马程序员课程的学习笔记整理而成。我特此声明,所有版权属于黑马程序员或相关权利人所有。本博客的目的仅为个人学习和交流之用,并非商业用途。
    • 我在整理学习笔记的过程中尽力确保准确性,但无法保证内容的完整性和时效性。本博客的内容可能会随着时间的推移而过时或需要更新。
    • 若您是黑马程序员或相关权利人,如有任何侵犯版权的地方,请您及时联系我,我将立即予以删除或进行必要的修改。
    • 对于其他读者,请在阅读本博客内容时保持遵守相关法律法规和道德准则,谨慎参考,并自行承担因此产生的风险和责任。
    • 本博客中的部分观点和意见仅代表我个人,不代表黑马程序员的立场。

    多任务

    • 多任务是指在同一时间内执行多个任务。
    • 多任务的优势:利用CPU资源,提高程序的执行效率
    • 多任务的形式:并发和并行

    并发概念

    • 并发:在一段时间内交替去执行多个任务
    • 对于单核cpu处理多任务,操作系统轮流让各个任务交替执行。假如:软件1执行0.01秒,切换到软件2,软件2执行0.01秒,再切换到软件3,执行0.01秒……这样反复执行下去 , 实际上每个软件都是交替执行的 。 但是,由于CPU的执行速度实在是太快了,表面上感觉就像这些软件都在同时执行一样 .。【单核cpu是并发的执行多任务的】
      在这里插入图片描述

    并行概念

    • 并行:在一段时间内真正的同时一起执行多个任务。

    • 对于多核cpu处理多任务,操作系统会给cpu的每个内核安排一个执行的任务,多个内核是真正的一起同时执行多个任务。这里需要注意多核cpu是并行的执行多任务,始终有多个任务一起执行。
      在这里插入图片描述

    进程

    • 在Python中,想要实现多任务可以使用多进程来完成。
    • 进程(Process):资源分配的最小单位,它是操作系统进行资源分配和调度运行的基本单位。通俗理解:一个正在运行的程序就是一个进程。例如:正在运行的qq , 微信等
    • 一个程序运行后至少有一个进程

    多线程的作用

    在这里插入图片描述
    在这里插入图片描述

    进程的创建步骤

    1. 导入进程包
      import multiprocessing
      
      • 1
    2. 通过进程类创建进程对象
      进程对象 = multiprocessing.Process() 
      
      • 1
    3. 启动进程执行任务
      进程对象.start()
      
      • 1

    通过进程类创建进程对象

    进程对象 = multiprocessing.Process(target=任务名) 
    
    • 1
    参数名说明
    target执行的目标任务名,这里指的是函数名(方法名)
    name进程名,一般不用设置
    group进程组,目前只能使用None
    # 导入进程模块
    import multiprocessing
    import time
    
    
    # 编写代码
    def coding():
        for i in range(3):
            print("coding...")
            time.sleep(0.2)
    
    
    # 听音乐
    def music():
        for i in range(3):
            print("music...")
            time.sleep(0.2)
    
    
    if __name__ == '__main__':
        # 通过进程类创建进程对象
        coding_process = multiprocessing.Process(target=coding)
        # 通过进程类创建进程对象
        music_process = multiprocessing.Process(target=music)
        # 启动进程
        coding_process.start()
        music_process.start()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    进程执行带有参数的任务

    进程执行带有参数的任务传参有两种方式:

    1. 元组方式传参 :元组方式传参一定要和参数的顺序保持一致。
    2. 字典方式传参:字典方式传参字典中的key一定要和参数名保持一致。
    参数名说明
    args以元组的方式给执行任务传参
    kwargs以字典方式给执行任务传参
    # 导入进程模块
    import multiprocessing
    import time
    
    
    # 编写代码
    def coding(num, name):
        for i in range(num):
            print(name)
            print("coding...")
            time.sleep(0.2)
    
    
    # 听音乐
    def music(count):
        for i in range(count):
            print("music...")
            time.sleep(0.2)
    
    
    if __name__ == '__main__':
        # 通过进程类创建进程对象
        coding_process = multiprocessing.Process(target=coding, args=(3, "传智"))
        # 通过进程类创建进程对象
        music_process = multiprocessing.Process(target=music, kwargs={"count": 2})
        # 启动进程
        coding_process.start()
        music_process.start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    获取进程

    • 进程编号的作用:当程序中进程的数量越来越多时 , 如果没有办法区分主进程和子进程还有不同的子进程 , 那么就无法进行有效的进程管理 , 为了方便管理实际上每个进程都是有自己编号的 .
    • 获取进程编号的两种方式
      1. 获取当前进程编号:os.getpid()
      2. 获取当前父进程编号:os.getppid()
    • 获取当前进程编号
    import os
    pid = os.getpid()
    print(pid)
    # 或者
    import multiprocessing
    pid = multiprocessing.current_process().pid
    print(pid)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 获取当前父进程编号
    def work() :
    # 查看当前进程
    current.process= multiprocessing.currentprocess()
    # 获取父进程的编号
    print(“work父进程的编号:, os.getppid())
    
    • 1
    • 2
    • 3
    • 4
    • 5

    杀死进程

    • os.kill() 方法用于向指定的进程发送信号。有两个参数:pidsignal
      • pid:要发送信号的进程的进程ID(PID)。
      • signal:要发送的信号的编号或常量。

    常见的一些信号编号或常量包括:

    • signal.SIGTERM:终止进程的请求信号(默认)。
    • signal.SIGKILL:强制终止进程的信号。
    • signal.SIGINT:中断进程的信号(通常由键盘上的Ctrl+C触发)。
    • signal.SIGSTOP:暂停进程的信号。

    要使用 os.kill() 方法,你需要导入 ossignal 模块:

    import os
    import signal
    
    • 1
    • 2

    以下是一个使用 os.kill() 方法终止进程的示例:

    import os
    import signal
    
    # 获取进程ID
    pid = 12345  # 替换为想杀死的进程的真实PID
    
    # 发送终止信号以终止进程
    os.kill(pid, signal.SIGTERM)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 请注意,os.kill() 方法只能用来发送信号给同一用户下的进程。如果要终止不属于当前用户的进程,需要具有适当的权限。
    • 在 Windows 系统上,os.kill() 方法只能终止由 Python 启动的子进程,对于其他进程,你可以使用 taskkill 命令来终止进程。

    进程间不共享全局变量

    • 在 Python 中,进程之间的全局变量默认是不共享的。这是因为进程是独立的执行单元,拥有自己的内存空间。

    • 实际上创建一个进程就是把主进程的资源进行拷贝产生了一个新的进程,这里主进程和子进程是相互独立的.

    • 由于进程之间拥有独立的内存空间,它们无法直接共享全局变量。因此,在写入数据的进程中修改 my_list,但在读取数据的进程中无法访问到修改后的值。

    在这里插入图片描述

    import multiprocessing
    import time
    
    # 全局变量
    my_list = []
    
    
    # 写入数据
    def write_data():
        for i in range(3):
            my_list.append(i)
            print("add:", i)
        print("write_data", my_list)
    
    
    # 读取数据
    def read_data():
        print("read_data", my_list)
    
    
    if __name__ == '__main__':
        # 创建写入数据进程
        write_process = multiprocessing.Process(target=write_data)
        # 创建读取数据进程
        read_process = multiprocessing.Process(target=read_data)
    
        # 启动进程执行相应任务
        write_process.start()
        time.sleep(1)
        read_process.start()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    add: 0
    add: 1
    add: 2
    write_data [0, 1, 2]
    read_data []
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 要实现进程间共享数据,你可以使用 multiprocessing 模块提供的进程间通信机制。
    import multiprocessing
    import time
    
    # 创建队列
    my_queue = multiprocessing.Queue()
    
    
    # 写入数据
    def write_data(queue):
        for i in range(3):
            queue.put(i)
            print("add:", i)
        print("write_data", list(queue.queue))
    
    
    # 读取数据
    def read_data(queue):
        print("read_data", list(queue.queue))
    
    
    if __name__ == '__main__':
        # 创建写入数据进程
        write_process = multiprocessing.Process(target=write_data, args=(my_queue,))
        # 创建读取数据进程
        read_process = multiprocessing.Process(target=read_data, args=(my_queue,))
    
        # 启动进程执行相应任务
        write_process.start()
        time.sleep(1)
        read_process.start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    主进程和子进程的结束顺序

    • 在Python中,主进程通常会等待所有非守护子进程执行结束后再结束,尤其是当使用multiprocessing模块时
    1. 非守护进程:
      • 当使用multiprocessing创建子进程时,这些进程默认是非守护进程。主进程会在所有非守护子进程结束后才结束。
      • 如果不显式地调用子进程的join()方法,主进程的结束仍然会等待这些子进程结束,尽管主进程的剩余部分代码已经执行完毕。
    2. join()方法:
      • 调用join()方法是一种显式等待子进程完成的方法。这会阻塞主进程直到对应的子进程结束。
      • 如果对所有子进程都调用了join(),那么主进程将会等待所有这些子进程结束后才继续执行。
    import multiprocessing
    import time
    
    
    # 工作函数
    def work():
        for i in range(10):
            print("工作中...")
            time.sleep(0.2)
    
    
    if __name__ == '__main__':
        # 创建子进程
        work_process = multiprocessing.Process(target=work)
        # 启动子进程
        work_process.start()
    	# 使用 join() 方法等待子进程完成
        work_process.join()
        # 延时1秒
        time.sleep(1)
        print("主进程执行完毕")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    设置守护进程

    • 为了保证子进程能够正常的运行,主进程会等所有的子进程执行完成以后再销毁,设置守护主进程的目的是主进程退出子进程销毁,不让主进程再等待子进程去执行。
    • 守护进程:
      • 守护子进程(daemon)的行为不同。如果子进程被设置为守护进程,主进程结束时不会等待这些子进程结束。
      • 守护进程适用于那些不重要的后台任务,这些任务不应阻止主进程退出。
    • 使用multiprocessing模块的Process类的daemon属性来设置守护进程。一个守护进程可以设置为在主程序退出的时候自动结束,即使它的工作还没有完成。对 daemon 属性的定义必须在 start() 调用之前进行,否则会抛出异常。
    import multiprocessing
    import time
    
    def work():
        while True:
            print("工作中...")
            time.sleep(0.2)
    
    if __name__ == '__main__':
        # 创建子进程
        work_process = multiprocessing.Process(target=work)
        
        # 设置为守护进程
        work_process.daemon = True
    
        # 启动子进程
        work_process.start()
    
        # 主进程暂停1秒
        time.sleep(1)
        
        print("主进程执行完毕")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    销毁子进程

    • 调用 terminate() 方法可以强制结束一个进程。这是一种比较粗暴的方式来停止一个进程,它不会给进程任何机会来清理它的资源(比如关闭文件句柄、结束子进程等)。一般建议只在必要的情况下使用 terminate() 方法。
    • 如果想在主程序中结束 work_process 进程,可以在 time.sleep(1) 后面加上 work_process.terminate() 调用。这样的话,即使 work_process 是非守护进程,它也会在主进程的指定时间后被强制结束。修改后的代码如下所示:
    import multiprocessing
    import time
    
    def work():
        while True:
            print("工作中...")
            time.sleep(0.2)
    
    if __name__ == '__main__':
        work_process = multiprocessing.Process(target=work)
        work_process.daemon = False  # 这里可以是 False 或 True,都不影响 terminate() 的效果
        work_process.start()
    
        time.sleep(1)  # 主进程暂停1秒
    
        # 强制结束子进程
        work_process.terminate()
    
        print("主进程执行完毕")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • work_process.terminate() 会在主进程休眠一秒后被调用,这时无论 work_process 是否还在执行,都会被立即终止。然后主进程继续执行,打印 “主进程执行完毕”。

    线程

    • 进程是分配资源的最小单位 , 一旦创建一个进程就会分配一定的资源 , 就像跟两个人聊QQ就需要打开两个QQ软件一样是比较浪费资源的 .
    • 线程是程序执行的最小单位 , 实际上进程只负责分配资源 , 而利用这些资源执行程序的是线程 , 也就说进程是线程的容器
    • 一个进程中最少有一个线程来负责执行程序 ,同时线程自己不拥有系统资源,只需要一些在运行中必不可少的资源。但它可与同属一个进程的其它线程共享进程所拥有的全部资源, 实现多任务的同时也节省了资源 .
      在这里插入图片描述

    线程的创建步骤

    1. 导入线程模块
      import threading
      
      • 1
    2. 通过线程类创建线程对象
      线程对象 = threading.Thread(target=任务名) 
      
      • 1
    3. 启动线程执行任务
      线程对象.start()
      
      • 1
    import threading
    
    def worker(num):
        """线程执行的目标函数"""
        print(f"Worker: {num}")
    
    # 创建线程对象
    t = threading.Thread(target=worker, args=(10,), kwargs={"key": "value"}, name="MyThread", daemon=True)
    
    # 启动线程
    t.start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    通过线程类创建线程对象

    threading.Thread 方法的主要参数及其描述:

    参数类型默认值描述
    target可选None指定线程要执行的函数
    args可选()传递给目标函数的参数,以元组形式
    kwargs可选{}传递给目标函数的关键字参数,以字典形式
    name可选None线程的名称,用于标识和调试
    daemon可选False指定线程是否为守护线程。如果是,线程不会阻止程序退出。

    线程执行带有参数的任务

    • 线程执行带有参数的任务传参有两种方式:
    1. 元组方式传参 :元组方式传参一定要和参数的顺序保持一致。
    2. 字典方式传参:字典方式传参字典中的key一定要和参数名保持一致。
    import time
    import threading
    
    
    # 编写代码
    def coding(num):
        for i in range(num):
            print("coding...")
            time.sleep(0.2)
    
    
    # 听音乐
    def music(count):
        for i in range(count):
            print("music...")
            time.sleep(0.2)
    
    
    if __name__ == '__main__':
        # 创建子线程
        coding_thread = threading.Thread(target=coding, args=(3,))
        music_thread = threading.Thread(target=music, kwargs={"count": 1})
    
        # 启动子线程执行任务
        coding_thread.start()
        music_thread.start()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    主线程和子线程的结束顺序

    • 主线程和子线程的结束顺序取决于子线程是否被设置为守护(Daemon)线程以及程序的设计。
    • 以下是两种情况的详细说明:
    1. 非守护(Non-Daemon)子线程:

      • 当主线程完成其执行代码但程序中还有非守护子线程在运行时,主线程会等待这些子线程完成后才正式结束。
      • 这意味着程序会在所有非守护子线程都完成其任务后才完全结束。
      • 在这种情况下,主线程的结束是条件性的,依赖于子线程的完成。
    2. 守护(Daemon)子线程:

      • 守护线程是为了服务于主线程的线程,它们在主线程的代码执行完毕后会自动终止。
      • 如果程序中所有的子线程都是守护线程,那么当主线程结束时,这些守护线程也会立即结束,不论它们的任务是否执行完成。
      • 在这种情况下,主线程不会等待守护子线程的完成,主线程结束后,整个程序也就结束了。
    • 如果子线程是非守护线程,则主线程会在这些子线程完成后结束。
    • 如果所有的子线程都是守护线程,则主线程结束时,整个程序也随之结束,不论守护子线程的状态如何。

    设置守护主线程

    • 设置守护主线程的目的是主线程退出子线程销毁,不让主线程再等待子线程去执行。

    设置守护主线程有两种方式:

    1. threading.Thread(target=work, daemon=True)(推荐)
    2. 线程对象.setDaemon(True)(弃用)
    import time
    import threading
    
    
    # 工作函数
    def work():
        for i in range(10):
            print("work...")
            time.sleep(0.2)
    
    
    if __name__ == '__main__':
        # 创建子线程
        # 方式1 参数方式设置守护主线程
        work_thread = threading.Thread(target=work, daemon=True)
        # work_thread = threading.Thread(target=work)
        # 方式2(不推荐)
        # work_thread.setDaemon(True)
         # 启动线程
        work_thread.start()
    
        # 延时一秒
        time.sleep(1)
        print("主线程执行完毕")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    线程间执行顺序

    在这里插入图片描述

    1. 线程之间执行是无序的,由CPU调度决定某个线程先执行的。
    2. 获取当前的线程信息
    # 通过current_thread方法获取线程对象
    current_thread = threading.current_thread()
    # 通过current_thread对象可以知道线程的相关信息,例如被创建的顺序
    print(current_thread)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    线程间共享全局变量

    • 多个线程都是在同一个进程中 , 多个线程使用的资源都是同一个进程中的资源 , 因此多线程间是共享全局变量
      在这里插入图片描述
    import threading
    import time
    
    
    # 全局变量
    my_list = []
    
    
    # 写入数据
    def write_data():
        for i in range(3):
            print("add:", i)
            my_list.append(i)
        print("write:", my_list)
    
    
    # 读取数据
    def read_data():
        print("read:", my_list)
    
    
    if __name__ == '__main__':
        # 创建子线程
        write_thread = threading.Thread(target=write_data)
        read_thread = threading.Thread(target=read_data)
    
        # 启动线程
        write_thread.start()
        # 延时一秒
        time.sleep(1)
        read_thread.start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    线程之间共享全局变量数据出现错误问题

    1. 定义两个函数,实现循环100万次,每循环一次给全局变量加1

    2. 创建两个子线程执行对应的两个函数,查看计算后的结果

    import threading
    
    # 全局变量
    g_num = 0
    
    
    # 对g_num进行加操作
    def sum_num1():
        for i in range(1000000):
            global g_num
            g_num += 1
    
        print("g_num1:", g_num)
    
    
    # 对g_num进行加操作
    def sum_num2():
        for i in range(1000000):
            global g_num
            g_num += 1
    
        print("g_num2:", g_num)
    
    
    if __name__ == '__main__':
        # 创建子线程
        sum1_thread = threading.Thread(target=sum_num1)
        sum2_thread = threading.Thread(target=sum_num2)
    
        # 启动线程
        sum1_thread.start()
        sum2_thread.start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    在这里插入图片描述

    • 解决办法:使用线程同步: 保证同一时刻只能有一个线程去操作全局变量
    • 线程同步方式:互斥锁

    互斥锁

    • 互斥锁: 对共享数据进行锁定,保证同一时刻只有一个线程去操作。
    • 互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到锁的线程进行等待,等锁使用完释放后,其它等待的线程再去抢这个锁。

    • 互斥锁的使用
    1. 互斥锁的创建

      mutex = threading.lock()
      
      • 1
    2. 上锁

      mutex.acquire()
      
      • 1
    3. 释放锁

      mutex.release()
      
      • 1
    import threading
    
    # 全局变量
    g_num = 0
    
    
    # 对g_num进行加操作
    def sum_num1():
        global g_num
        for i in range(1000000):
            # 上锁
            mutex.acquire()
            g_num += 1
            # 解锁
            mutex.release()
    
    
    # 对g_num进行加操作
    def sum_num2():
        global g_num
        for i in range(1000000):
            # 上锁
            mutex.acquire()
            g_num += 1
            # 解锁
            mutex.release()
    
    
    if __name__ == '__main__':
        # 创建锁
        mutex = threading.Lock()
    
        # 创建子线程
        sum1_thread = threading.Thread(target=sum_num1)
        sum2_thread = threading.Thread(target=sum_num2)
    
        # 启动线程
        sum1_thread.start()
        sum2_thread.start()
    
        # 等待线程执行结束
        sum1_thread.join()
        sum2_thread.join()
    
        # 打印结果
        print("g_num1:", g_num)
        print("g_num2:", g_num)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    死锁

    • 一直等待对方释放锁的情景就是死锁

    • 死锁的结果:会造成应用程序的停止响应,不能再处理其它任务。
      在这里插入图片描述

    • 产生死锁的原因:没有及时或者在正确的位置释放锁

    • 死锁的注意点

      • 死锁一旦产生就会造成应用程序的停止响应,应用程序无法再继续往下执行
      • 使用互斥锁的时候需要注意死锁的问题,要在合适的地方注意释放
    • 举例

    import threading
    
    
    # 全局变量
    g_num = 0
    
    
    # 对g_num进行加操作
    def sum_num1():
        # 上锁
        print("sun_num1...")
        mutex.acquire()
    
        for i in range(1000000):
            global g_num
            g_num += 1
    
        print("g_num1:", g_num)
    
    
    # 对g_num进行加操作
    def sum_num2():
        # 上锁
        print("sun_num2...")
        mutex.acquire()
    
        for i in range(1000000):
            global g_num
            g_num += 1
    
        print("g_num2:", g_num)
    
    
    if __name__ == '__main__':
        # 创建锁
        mutex = threading.Lock()
        # 创建子线程
        sum1_thread = threading.Thread(target=sum_num1)
        sum2_thread = threading.Thread(target=sum_num2)
    
        # 启动线程
        sum1_thread.start()
        sum2_thread.start()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    线程和进程对比

    下面是一个简单的表格来对比进程和线程:

    进程线程
    关系线程是依附在进程里面的一个进程默认提供一条线程,进程可以创建多个线程
    区别进程之间不共享全局变量线程之间共享全局变量,但要注意资源竞争问题
    创建进程的资源开销大创建线程的资源开销相对较小
    进程是操作系统资源分配的基本单位线程是CPU调度的基本单位
    进程可以独立执行线程不能独立执行,必须依托在进程中
    优缺点优点:可以利用多核资源优点:资源开销小
    缺点:资源开销大缺点:不能使用多核

    总结:

    • 进程是操作系统资源分配的基本单位,用于执行程序。进程之间通常是独立的,不共享全局变量,创建进程的资源开销较大,但可以利用多核资源。
    • 线程是进程内的执行单元,一个进程可以有多个线程,线程之间共享全局变量,但要注意资源竞争问题。创建线程的资源开销相对较小,但不能利用多核资源。
    • 进程和线程各有优缺点,选择使用哪种方式要根据具体场景和需求来决定。进程适用于需要独立执行的任务,而线程适用于需要共享数据或并发执行的任务。
  • 相关阅读:
    心酸,1区期刊主编,诺奖得主:成名前论文只能发表在IF低于1.5的期刊上
    Mastering the Art of Convolutional Neural Networks: A Hands-On Exploration
    c++初阶-----STL---string的模拟实现
    新学期的分享,立个flag吧
    网络 IO 演变过程
    分段权重和变异反向学习的蝴蝶优化算法-附代码
    最全电脑固态硬盘SSD入门级白皮书
    【Linux command 05】seq Command on Linux
    Sora 使用教程,新手小白可用
    神经网络解决实际问题,神经网络常见问题
  • 原文地址:https://blog.csdn.net/yang2330648064/article/details/134494631