• Python-进程和线程


    张钊*,沈啸彬*, 王旭* 李月,曹海艳,

    (淮北师范大学计算机科学与技术学院,淮北师范大学经济与管理学院,安徽 淮北)

    *These authors contributed to the work equllly and should be regarded as co-first authors.
     

    🌞欢迎来到python的世界 
    🌈博客主页:卿云阁

    💌欢迎关注🎉点赞👍收藏⭐️留言📝

    🌟本文由卿云阁原创!

    🌠本阶段属于练气阶段,希望各位仙友顺利完成突破

    📆首发时间:🌹2022年12月1日🌹

    ✉️希望可以和大家一起完成进阶之路!

    🙏作者水平很有限,如果发现错误,请留言轰炸哦!万分感谢!


    目录

    🍈 多任务操作系统

    🍉何为进程?何为线程?

    🍊Python的多进程multiprocessing (包)

    1.Process——进程类

    🍋获取当前进程的编号

    🍔多线程Threading模块

    1.多线程的类Thread类

    🍿继承Thread类

    🥓python提供了多种进程通信

    进程线程有多重要?
          刚开始学Python的时候你可能还没有感觉到,因为你写的代码从上到下 执行一遍就可以了,但实际上这很初级,实际开发写项目的时候,为了充分利用电脑配置来 加快程序进度,我们往往会用到多进程多线程。但是实话实说,博主学习这个的原因是因为项目的需要,我是做了一个项目,需要目标检测和测距并配合语音进行输出,一开始时我是把语音直接加在目标检测的后面,但是这产生了延迟的问题,为了解决这个问题,我开始学习这个知识点。

    🍈 多任务操作系统

        操作系统可以执行多个任务,比如我们的Windows系统,除了目前在执行的、你能看得到的 几个任务,还有很多后台正在执行的任务,可以用Ctrl+Alt+Del键调出任务管理器看一下就知道了。
       我的电脑配置经常会看到有几核处理器的属性,例如我的电脑是8核的,也就是说电脑最多能同时执行8个任务,最多运行8个进程同时进行。

     但为什么我们的电脑却能够同时运行几百个任务呢?

    其实这得益于于操作系统的任务调度,大部分的操作系统是采用抢占时间片的形式进行调
    。系统在极其微小的时间内,在多个任务之间进行极快速的切换,比如说8核的操作系统理
    论上1秒钟之内只能同时执行8个任务,但是系统在1秒钟之内可能在上百个任务之间进行切
    换,A任务执行一下、B任务执行一下、C任务执行一下......结果1秒钟之内很多任务都能被执
    行到,造成了肉眼可见的几百个任务在一直执行。 术语叫“宏观并行,微观串行”,实际上电脑在极端的时间内只能执行不超过配置核数的任 务数,8核还是只能执行8个任务。

     🍉何为进程?何为线程?

       进程就是任务,1个进程就相当于1个任务,是操作系统分配资源的最 小单位。在python中,想要实现多任务可以使用进程来完成,进程是实现多任务的一种方式。
       进程的多个子任务就称之为线程,线程是进程的最小执行单位, 一个进程可以有很多线程, 每个线程执行的任务都不一样。Python既支持多进程又支持多线程

    🍊Python的多进程multiprocessing (包)

         如果你利用多进程,你的Python代码是从头到尾逐行执行的,这其实就是在执行1个进程, 这一点应该很好理解。 要想更多利用CPU资源,我们可以利用多进程,这里介绍一个Python多进程时常用的包 multiprocessing,它拥有很多的功能,比如子进程、通讯、共享、执行不同的形式等等,我们来了解一些常用的。

    1.Process——进程类

    Process是multiprocessing里面的一个进程类,通过它就能实现多进程。
    Process(target,name,args,kwargs)
    • target是目标,在哪里新开进程让系统去执行?得给系统一个目标。
    • name是进程的名字,你可以设置也可以不设置,默认是Process-N,N是从 1,2,3....N,系统默认从小到大取名。
    • args和kwargs是参数,可用于传递到目标。
    Process里面有很多方法,其中最常用的就是start()启动进程的方法。
    进程名.start() #开始进程
    举例:写好的代码如下,我想看看开启和没开启多进程调用函数的效果。
    1. import time
    2. #2个要同时执行的函数
    3. def music() :
    4. for i in range(5): #执行5
    5. print("听音乐中...")
    6. time.sleep(0.2) #延迟0.2s,目的是让效果对比更明显一些
    7. def movie():
    8. for i in range(5):
    9. print("看视频中...")
    10. time.sleep(0.2) #延迟0.2s
    11. music()
    12. movie()
    13. print("主进程执行完毕")
    可以看到,这是很正常的运行情况,程序从上运行到下,逐行运行,music()里面的三次循环
    没有执行完毕就不会执行movie()里面,以及这两个函数如果没有执行完毕,就不会执行
    最后一行的print("主进程执行完毕")。

    我们再来看在上面案例的代码中加入多进程:
    1. import time
    2. import multiprocessing
    3. # 2个要同时执行的函数
    4. def music():
    5. for i in range(5): # 执行5
    6. print("听音乐中...")
    7. time.sleep(0.2) # 延迟0.2s,目的是让效果对比更明显一些
    8. def movie():
    9. for i in range(5):
    10. print("看视频中...")
    11. time.sleep(0.2) # 延迟0.2s
    12. if __name__ == "__main__": # 解决Windows系统下调用包时的递归问题
    13. # 创建子进程
    14. music_process = multiprocessing.Process(target=music)
    15. movie_process = multiprocessing.Process(target=movie)
    16. # 启用进程
    17. music_process.start()
    18. movie_process.start()
    19. print("主进程执行完毕")

    运行效果:

    可以看出来,这开启进程之后,代码运行时是有3个进程同时进行的,一个是从上往下执行的
    主进程,执行到下面输出“主进程执行完毕”,另外两个子进程去执行music()和movie()
    进程,从他们的执行速度来看,它们是同时在进行的,所以没有像刚才那样非要等其中一个
    函数里面的代码执行3遍才开始第2个函数。

    🍋获取当前进程的编号

        前面我们讲到了代码执行时有多个进程在同时进行任务,那么怎么样查看当前进程的编号来得知目前有哪些进程在运行呢?哪些是主进程哪些是子进程呢?3个方法,我们先来看一下方 法,后面再结合例子一起使用。
    (1)获取当前进程的编号:
    需要用到一个os模块里面的getpid()方法,用法如下:
    os.getpid()
    (2)获取当前进程的名字
    这里用的还是multiprocessing包,里面有个current_process()的方法,用法如下:
    multiprocessing.current_process()

    (3)获取当前父进程(主进程)的编号
    子进程是属于哪个父进程的?这个用的是os模块里面的getppid() ,用法如下:
    os.getppid()
    那么方法都看到了,我们来在刚才的例子的基础上,获取并打印一下当前进程的名字、编号
    以及父进程的编号。
    运行结果:

    🍔多线程Threading模块

    多进程能同时运行几个任务,前面我们讲过进程的最小单位是线程,那么线程也同样可以进
    行多个任务。如果一个进程只有1个任务(主进程),那么也可以说是只有1个线程,就比如
    我们不使用多进程运行代码的时候,这时候就可以说1个主进程或1个主线程。

    1.多线程的类Thread类

    多线程常用的一个模块是threading,里面有个教Thread的类,跟前面我们将多进程时用到
    的Process类差不多,我们先来看看用法:
    Thread(target=None,name=None,args=(),kwargs=None)
    • target:可执行目标
    • name:线程的名字默认Thread-N
    • args/kwargs:目标参数
    同样的,多线程也要有开启的方法,跟前面的也差不多:
    start()
    还有获取线程名字的方法:
    threading.current_thread()
    知道了这些知识点,我们开始举例:用跟上面差不多的例子去使用一下我们的多线程。
    1. import threading,time
    2. def music(name,loop):
    3. for i in range(loop):
    4. print("听音乐 %s , 第%s次"%(name,i))
    5. time.sleep(0.2)
    6. def movie(name,loop):
    7. for i in range(loop):
    8. print("看电影%s , 第%s次"%(name,i))
    9. time.sleep(0.2)
    10. if __name__ =="__main__":
    11. music_thread = threading.Thread(target=music,args=("最亲的人",3))
    12. movie_thread = threading.Thread(target=movie,args=("唐探2",3))
    13. music_thread.start()
    14. movie_thread.start()
    15. print("主线程执行完毕")

    可以看出来,我们的多线程其实是跟多进程差不多的,同样可以运行多个任务,这里我们还
    增加了参数的使用。

    🍿继承Thread类

    我们除了用上面的方法实现多线程任务,还可以用继承类的方式去实现多线程。
    举例:通过多线程的方式,去打印“凉凉”和“头发没了"。
    MyThread这个类是我们自己创建的,它是继承于父类threading.Thread
    1. import threading,time
    2. #多线程的创建
    3. class MyThread(threading.Thread):
    4. def __init__(self,name): #初始化
    5. super().__init__() #调用父类Thread的初始化方法
    6. self.name = name #name变成实例属性
    7. def run(self):
    8. #线程要做的事情
    9. for i in range(5):
    10. print(self.name)
    11. time.sleep(0.2)
    12. #实例化子线程
    13. t1 = MyThread("凉凉")
    14. t2 = MyThread("头发没了")
    15. t1.start()
    16. t2.start()

    运行结果:
    随机效果是有的,你们的效果和我的可能会不一样,每台电脑在运行多线程代码时,哪个线
    程能够抢到时间片谁就先执行。 通过类Thread继承一样可以实现多线程。

    🥓python提供了多种进程通信

     一般来说进程之间是并行的,在实际的工程中时,常常是两个进程之间是有一定关系的,比如我现在需要完成任务一(进程1——>进程2进行加工和处理),所以必须然后让进程之间通信,此时我们必须要搭建一个桥梁,这个时候我就需要用到数据结构,队列。

      再比如博主做的项目中,语音播报模块需要等目标检测模块中的值,这个时候我们应该怎么办呢?这里就涉及到进程的通信。python提供了多种进程通信的方式,主要Queue和Pipe这两种方式,Queue用于多个进程间实现通信,Pipe是两个进程的通信。

    Queue有两个方法:

    • Put方法:以插入数据到队列中,他还有两个可选参数:blocked和timeout。

    • Get方法:从队列读取并且删除一个元素。同样,他还有两个可选参数:blocked和timeout。

    1. from multiprocessing import Process, Queue, set_start_method
    2. import time,random,os
    3. #创建队列,容量为3
    4. q=Queue(3)
    5. q.put(1)
    6. q.put(2)
    7. q.put(3)
    8. q.put(4,timeout=3)#一直没执行,意思是等待3秒。

    1. from multiprocessing import Process, Queue, set_start_method
    2. import time,random,os
    3. #创建队列,容量为3
    4. q=Queue(3)
    5. q.put(1)
    6. q.put(2)
    7. q.put(3)
    8. print(q.qsize())
    9. while True:
    10. if not q.empty():
    11. print(q.get())
    12. else:
    13. print("该队列已为空")
    14. break

     

    举个栗子:

    比如现在我有一个任务是下载音乐然后保存音乐:

    1. from multiprocessing import Process, Queue, set_start_method
    2. import time,random,os
    3. #下载音乐
    4. def load_music(q):
    5. music_list=["1","2","3","4","5"]
    6. for i in music_list:
    7. print('正在下载<{}>音乐'.format(i))
    8. q.put(i)#把下载好的音乐存入队列
    9. #保存音乐
    10. def save_music(q):
    11. while True:
    12. if not q.empty():
    13. print('把<{}>音乐存入D盘'.format(q.get()))
    14. else:
    15. print("该队列已为空")
    16. break
    17. if __name__ == '__main__':
    18. q=Queue(4)
    19. p1 = Process(target=load_music,name='目标检测',args=(q,))
    20. p2 = Process(target=save_music,name='保存音乐',args=(q,))
    21. #启动子进程,写入
    22. p1.start()
    23. p2.start()

     

    再举一个我项目中的例子:

    1. from multiprocessing import Process, Queue, set_start_method
    2. import time,random,os
    3. #目标检测
    4. def load(q1,q2):
    5. state_list=["red","green"]
    6. dis_list=["1", "2", "3", "4", "5"]
    7. for i in state_list:
    8. print('检测当前的状态<{}>'.format(i))
    9. q1.put(i)#把当前的状态存入队列
    10. for i in dis_list:
    11. print('检测当前的距离<{}>'.format(i))
    12. q2.put(i)#把当前的状态存入队列
    13. #语音播报
    14. def save(q1,q2):
    15. while True:
    16. if not q1.empty():
    17. print('把状态<{}>语音播报'.format(q1.get()))
    18. else:
    19. print("该队列已为空")
    20. break
    21. while True:
    22. if not q2.empty():
    23. print('把距离<{}>语音播报'.format(q2.get()))
    24. else:
    25. print("该队列已为空")
    26. break
    27. if __name__ == '__main__':
    28. q1=Queue(2)
    29. q2=Queue(5)
    30. p1 = Process(target=load,name='目标检测',args=(q1,q2,))
    31. p2 = Process(target=save,name='语音播报',args=(q1,q2,))
    32. #启动子进程,写入
    33. p1.start()
    34. p2.start()

    结语:
         上面的三种方式均可以实现多个任务的同时进行,对于初学者来说,个人认为找到一个适合自己使用习惯的就可以了。

    Institutional Review Board Statement: Not applicable.

    Informed Consent Statement: Not applicable.

    Data Availability Statement: Not applicable.

    Author Contributions:All authors participated in the assisting performance study and approved the paper.

    Conflicts of Interest: The authors declare no conflict of interest
     

  • 相关阅读:
    Navicat Premium 16.X--不错的数据库工具
    刷题记录:牛客NC14704美味菜肴
    【论文阅读】Densenet:Densely Connected Convolutional Networks 密集连接的卷积网络
    MyBatis
    Kotlin中函数的基本用法以及函数类型
    弘辽科技:网店如何补流量?需要有什么准备?
    数组常见算法代码总结
    Linux的进程调度实现
    python3GUI--仿做一个网易云音乐(第三弹v2.0)By:PyQt5(附下载地址)
    acm拿国奖的第一关:数组和字符串
  • 原文地址:https://blog.csdn.net/zzqingyun/article/details/128139911