开发者

python网络编程之进程详解

开发者 https://www.devze.com 2022-12-08 10:43 出处:网络 作者: Top Secret
目录1.进程1.1进程:1.2在python中创建进程1.3 使用multiprocessing创建进程1.3.1 单个进程时: 1.3.2 多个子进程时:1.3.3 自定义进程类方法使用Process子类创建进程Process(target=test)实现多进程,复杂的要
目录
  • 1.进程
    • 1.1进程:
    • 1.2在python中创建进程
    • 1.3 使用multiprocessing创建进程
      • 1.3.1 单个进程时: 
      • 1.3.2 多个子进程时:
      • 1.3.3 自定义进程类方法
    • 使用Process子类创建进程Process(target=test)实现多进程,复杂的要定义一个类继承Process,每次实例化这个类的时候就等同于实例化一个进程对象 
      • 1.4 Pool进程池
      • 2. 验证进程是否能共享信息
        • 2.1 Queue(队列)模块:
          • 2.1.1 队列简介:
            • 2.2 实现进程间的通信
            • 总结

              python网络编程之进程详解

              1.进程

              它们的主要作用:多任务同时执行

              python网络编程之进程详解

              1.1进程:

              Windows打开的程序就是一个进程例如打开qq 打开微信

              如果打开2个qq代表打开了2个进程

              1.2在python中创建进程

              只能linux 使用os.fork()用这个可以创建多进程

              Linux/Windows使用multiprocessing模块和Pool进程池(他俩是跨平台模块)

              1.3 使用multiprocessing创建进程

              1.3.1 单个进程时: 

              from multiprocessing import Process #从multiprocessing库中导入Process模块
              #执行进程代码
              #一个子进程
              def test(interval):
                  print("我是一个子进程")
               
              #执行主程序
              def main():
                  print("主进程启动")
                  p = Process(target=test,args=(1,)) #使用进程模块,目标参数target为子进程函数
                  p.start() #启动子进程
                  print("主进程结束")
               
              if __name__ == '__main__': 
                  main()
              """
              >>> runfile('D:/python_files/python_fiew/网络编程_01.py', wdir='D:/python_files/python_fiew')
              主进程启动
              主进程结束
              我是一个子进程
              """

              1.3.2 多个子进程时:

              from multiprocessing import Process
              import time,os
              #子进程1
              def child_1(interval):
                  print("子进程(%s)开始执行,父进程为(%s)"%(os.getpid(),os.getpid())) #os.getpid()为获取进程号
                  t_stat = time.time() #计时开始
                  time.sleep(interval) #程序将被挂起n秒
                  t_end = time.time() #计时结束
                  print("子进程(%s)的执行时间为'%0.2f'秒"%(os.getpid(),t_end-t_stat))
              #子进程2
              def chlid_2(interval):
                  print("子进程(%s)开始执行,父进程为(%s)"%(os.getpid(),os.getpid()))
                  t_stat = time.time()
                  time.sleep(interval)
                  t_end = time.time()
                  print("子进程(%s)的执行时间为(%0.2f)"%(os.getpid(),t_end-t_stat))
               
              if __name__ == '__main__':
                  print("-----父进程开始执行-------")
                  print("父进程启动时,父进程PID为:(%s)"%(os.getpid()))  #打印父进程启动时父进程的PID
                  p1 = Process(target=child_1,args=(1,)) #实例化子进程1
                  p2 = Process(target=chlid_2,args=(1,)) #实例化子进程2
                  p1.start() #启动子进程1
                  p2.start() #启动子进程2
                  #此时父进程仍然在执行
                  print("pi.is_alive=%s"%(p1.is_alive()))  #p1.is_alive() 判断子进程p1是否还在执行,执行则返回ture
                  print("p2_is_alive=%s"%(p2.is_alive()))
                  #输出此时进程执行过程中的PID(进程号)
                  print("执行过程中的p1的进程号p1.pid=%s"%(p1.pid))
                  print("执行过程中的p2的进程号p2.pid=%s" % (p2.pid))
                  print("---等待子进程结束----")
                  p1.join() #等待子程序p1结束
                  p2.join()
                  print("父进程结束,此时父进程的进程号为:(%s)"%(os.getpid()))
              #总结:#os.getpid()为获取进程号   #p1.is_alive() 判断子进程p1是否还在执行,执行则返回ture

              python网络编程之进程详解

              由运行结果分析:子进程在执行的过程中,进程号不变。父进程号在启动时,和在结束所有子进程时 相同,而当子进程同时执行时,父进程号会动态变化。

                    挂起进程在 操作系统中可以定义为暂时被淘汰出 内存的进程,机器的资源是有限的,在资源不足的情况下,操作系统对在内存中的程序进行合理的安排,其中有的进程被暂时调离出内存,当条件允NtBwdbLSNU许的时候,会被操作系统再次调回内存,重新进入等待被执行的状态即就绪态,系统在超过一定的时间没有任何动作。 

              1.3.3 自定义进程类方法

              使用Process子类创建进程Process(target=test)实现多进程,复杂的要定义一个类继承Process,每次实例化这个类的时候就等同于实例化一个进程对象 

              (解决上一个程序中两个子进程重复代码的问题) 

              from multiprocessing import Processimport time,os#继承Process类class SubProcess(Process):    def __init__(self,interval,name=""): #子类SubProcess的构造方法        Process.__init__(self) #Process.__init__(self) #继承父类的构造方法        self.interval = interval        self.name = name         #重写父类方法    def run(self):        print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getpid()))  # os.getpid()为获取进程号        t_stat = time.time()  # 计时开始        time.sleep(self.interval)  # 程序将被挂起n秒        t_end = time.time()  # 计时结束        print("子进程(%s)的执行时间为'%0.2f'秒" % (os.getpid(), t_end - t_stat))if __name__ == '__main__':    print("-----父进程开始执行-------")    print("父进程启动时,父进程PID为:(%s)"%(os.getpid()))  #打印父进程启动时父进程的PID    p1 = SubProcess(interva编程客栈l=1,name='ZARD1') #实例化子进程1    p2 = SubProcess(interval=2,name=('ZARD2')) #实例化子进程2    p1.start() #启动子进程1    p2.start() #启动子进程2    #此时父进程仍然在执行    print("pi.is_alive=%s"%(p1.is_alive()))  #p1.is_alive() 判断子进程p1是否还在执行,执行则返回ture    print("p2_is_alive=%s"%(p2.is_alive()))    #输出此时进程执行过程中的PID(进程号)    print("p1.name = %s"%(p1.name))    print("执行过程中的p1的进程号p1.pid=%s"%(p1.pid))    print("p2.name = %s" % (p2.name))    print("执行过程中的p2的进程号p2.pid=%s" % (p2.pid))    print("---等待子进程结束----")    p1.join() #等待子程序p1结束    p2.join()    print("父进程结束,此时父进程的进程号为:(%s)"%(os.getpid()))from multiprocessing import Process
              import time,os
               
              #继承Process类
              class SubProcess(Process):
                  def __init__(self,interval,name=""): #子类SubProcess的构造方法
                      Process.__init__(self) #Process.__init__(self) #继承父类的构造方法
                      self.interval = interval
                      self.name = name
                   
                  #重写父类方法
                  def run(self):
                      print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getpid()))  # os.getpid()为获取进程号
                      t_stat = time.time()  # 计时开始
                      time.sleep(self.interval)  # 程序将被挂起n秒
                      t_end = time.time()  # 计时结束
                      print("子进程(%s)的执行时间为'%0.2f'秒" % (os.getpid(), t_end - t_stat))
               
              if __name__ == '__main__':
                  print("-----父进程开始执行-------")
                  pr编程客栈int("父进程启动时,父进程PID为:(%s)"%(os.getpid()))  #打印父进程启动时父进程的PID
                  p1 = SubProcess(interval=1,name='ZARD1') #实例化子进程1
                  p2 = SubProcess(interval=2,name=('ZARD2')) #实例化子进程2
                  p1.start() #启动子进程1
                  p2.start() #启动子进程2
                  #此时父进程仍然在执行
                  print("pi.is_alive=%s"%(p1.is_alive()))  #p1.is_alive() 判断子进程p1是否还在执行,执行则返回ture
                  print("p2_is_alive=%s"%(p2.is_alive()))
                  #输出此时进程执行过程中的PID(进程号)
                  print("p1.name = %s"%(p1.name))
                  prhttp://www.cppcns.comint("执行过程中的p1的进程号p1.pid=%s"%(p1.pid))
                  print("p2.name = %s" % (p2.name))
                  print("执行过程中的p2的进程号p2.pid=%s" % (p2.pid))
                  print("---等待子进程结束----")
                  p1.join() #等待子程序p1结束
                  p2.join()
                  print("父进程结束,此时父进程的进程号为:(%s)"%(os.getpid()))

              python网络编程之进程详解

              代码分析: 

              python网络编程之进程详解

              1.4 Pool进程池

              (解决当要创造成百上千个进程的情况)  

              例子: 有三个水槽 ,要接10桶水,我们最多只能同时接3盆,第10盆随便找一个盆,其他两个闲置。

              from multiprocessing import Pool #导入进程池
              import os,time
               
              def task(name):
                  print("子进程(%s)执行task %s..."%(os.getpid(),name))
                  time.sleep(2) #休眠2秒
               
              if __name__ == '__main__':
                  print("---父进程(%s)启动---"%(os.getpid()))
                  p = Pool(3)  #定义一个进程池,一次最多容纳三个进程,即一次最多可同时执行三个子进程
                  for i in range(10):
                      p.apply_async(task,args=(i,)) #使用非阻塞的方式调用task
                  print("---等待所有子进程结束---")
                  p.close() #关闭进程池,关闭后进程池不再接收新的请求
                  p.join() #等待子进程结束
                  print("全部子进程结束")

              python网络编程之进程详解

              小结:定义一个进程池,并规定一个池子中可以同时执行多少个进程,可以实现多个进程分批次的执行。 

              注意:

              (1)区分使用Process模块与使用进程池模块Pool的区别 

              (2)对于实例对象 p,p.start()表示开始执行进程;p.join()表示结束进程

              (3)注意加强阻塞与非阻塞知识点的学习

              2. 验证进程是否能共享信息

              引例: 

              from multiprocessing import Process
               
              #子进程1
              def plus():
                  print("---子进程1开始执行---")
                  global g_num #声明全局变量
                  g_num += 50
                  print("在子进程1下:g_num = %d"%(g_num))
                  print("---子进程1结束运行---")
               
              #子进程2
              def minus():
                  print("---子进程2开始执行---")
                  global g_num #声明全局变量
                  g_num -= 50
                  print("在子进程2下:g_num = %d"%(g_num))
                  print("---子进程2结束运行---")
               
              g_num = 100 #赋值全局变量
              if __name__ == '__main__':
                  print("---主进程启动---")
                  print("在主进程运行中,g_num = %d"%(g_num))
                  child1 = Process(target=plus) #实例化子进程1
                  child2 = Process(target=minus)  # 实例化子进程2
                  child1.start() #启动子进程1
                  child2.start()
               
                  child1.join() #等待子进程结束
                  child2.join()
                  print("---主进程结束---")

              python网络编程之进程详解

              由以上例子可见,对于进程1,2而言,全局变量g_num并不互相影响。即有如下关系:

              python网络编程之进程详解

              那么就有如下问题了,思考:如何才能实现进程之间的通讯?

              答:通过 multiprocessing Queue(队列), Pipes(管道), 接下来主要演示 Queue(队列)模块。

              2.1 Queue(队列)模块:

              2.1.1 队列简介:

              python网络编程之进程详解

              1.新来的排队的在队尾

              2.最前面的完成离队后,后面一个跟上

              多进程队列的使用Queue, 本身他就是一个消息队列程序 :

              python网络编程之进程详解

              实践: 当Queue(3)时:

              from multiprocessing import Queue #导入队列模块
              if __name__ == '__main__':
                  q = Queue(3) #初始化一个Queue对象,最多只能接受3条put信息
                  #消息写入队列
                  q.put("消息1") #将此消息1写入队列
                  q.put("消息2")
                  print(q.full()) #q.full() 是验证队列是否已满  没满则返回False
                  q.put("消息3")  #将此消息3写入队列
                  print(q.full()) #q.full() 是验证队列是否已满  满了则返回Ture
               
                  #利用try看看队列已满是否还可再塞入信息
                  try:
                      q.put("尝试塞入第4条信息",True,1) #可能出问题的代码
                  except:
                      print("尝试利用q.put()向队列中继续添加信息:")
                      print("队列已满,现有消息数量为:%d,无法继续添加信息。"%(q.qsize()))  #q.qsize() 返回队列中的已有信息数量
               
                  try:
                      q.put_nowait("尝试塞入第4条信息")  # 可能出问题的代码
                  except:
                      print("尝试利用q.put_nowait()向队列中继续添加信息:")
                      print("队列已满,现有消息数量为:%d,无法继续添加信息。" % (q.qsize()))  # q.qsize() 返回队列中的已有信息数量
               
                  #获取(打印)队列中的信息
                  if not q.empty():
                      print("---从队列中读取信息---")
                      for i in range(q.qsize()):  #循环打印队列信息
                          print(q.get_nowait())  #q.get_nowait() 读取队列信息
               
               
               

              python网络编程之进程详解

              解决:

              python网络编程之进程详解

               

              python网络编程之进程详解

              当Queue(4)时,打印的结果如下,可编程客栈见此时可继续向队列中塞入第4条信息。

              python网络编程之进程详解

              小结:

              multiprocessing.Process 可以创建多进程,使用multiprocessing Queue可以实现队列操作。

              2.2 实现进程间的通信

              from multiprocessing import Process,Queue
              import time
               
              #子进程1:向队列中写入数据
              def write_date(q):
                  if not q.full(): #若队列没满,则写入数据
                      for i in range(5):
                          date = "数据" + str(i)
                          q.put(date) #向队列中写入数据
                          print("已写入:%s" % date)
              #子进程2:向队列中读取数据
              def read_date(q):
                  time.sleep(1)  # 休眠1s
                  while not q.empty():
                      print("读取:%s" % q.get(True, 2))  # 等待2s,如果还没读取到消息,抛出异常
               
              #主程序
              if __name__ == '__main__':
                  print("---主程序启动---")
                  q = Queue()  # 父进程创建Queue,并传给各个子进程
                  write_child = Process(target=write_date,args=(q,)) # 实例化进程对象,其中args=(q,)表示把队列传给子进程1
                  read_child = Process(target=read_date,args=(q,))
                  write_child.start()  # 启动子进程1,写入
                  read_child.start()  # 启动子进程2,读取
                  write_child.join()  # 等待子进程1结束
                  read_child.join()  # 等待子进程2结束
                  print('-----父进程结束-----')
               

              python网络编程之进程详解

              小结:

              (1)进程之间可以通过队列来实现通信,但需要注意的是,队列中的信息遵循“先进先出”的原则。如上数据那样,先写入数据0,则最先读出的数据也是数据0;

              (2)如:

              python网络编程之进程详解

               在父进程中创建队列,再利用Process模块实例化子进程对象,target参数为子进程的函数名,args参数即为队列。

              总结

              本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

              0

              精彩评论

              暂无评论...
              验证码 换一张
              取 消