zoukankan      html  css  js  c++  java
  • 10_python进程

    1. 并发:多个进程同时在执行,如执行python文件时,启动多个进程,操作系统管理多个进程;

           1> 同步: 可以理解成在多条车道(进程/线程)上,就只有一辆车在开,按代码的逻辑分支先在A车道跑,之后再走到B车道...

            2> 异步: 可以理解成在多条车道上,有多辆车在开,各自路各自的

            3> os.getpid():查看当前进程的进程号;

            4> os.getppid()):查看当前进程的父进程号;

            5> 以下代码进程的生命周期:

                  a> 主进程开启子进程后,主进程执行自己后面的代码;

                  b> 而子进程等到操作系统调度后执行自己的代码;

                   c> 此时主进程和子进程都是在各自执行自己的代码 -- 异步;

                   e> 子进程执行时间长时,主进程会在主进程代码执行完毕后等待子进程执行完毕之后,主进程才会结束;

     1 import os
     2 import time
     3 from multiprocessing import Process
     4 def func():
     5     print('子进度启动...')
     6     time.sleep(2)
     7     print('子进程id:',os.getpid())  #查看当前进程的进程号
     8     print('子进程的父进程:', os.getppid())
     9     print('子进度结束...')
    10 
    11 if __name__ == '__main__':
    12     print('执行当前脚本的进程(父进程),开始:',os.getpid())
    13     p = Process(target=func)  #注册
    14     p.start()    #启动一个子进程,func方法在该子进程中执行
    15     print('执行当前脚本的进程(父进程),结束:',os.getpid())
    16     print('父进程的父进程id:',os.getppid())  # 查看当前进程的父进程,即pycharm工具的进程id
    17     # 从执行打印出来的信息可见, 主进程启动后,注册了一个子进度,没有等子进程启动执行func方法,就去执行自己的代码
    18     # 子进程从就绪状态到执行状态,执行代码后,结束子进程
    19     # 故主进程和子进程是异步的,不是同步的
    启动多个进程

            6> 带参数启动多进程: p = Process(target=func,args=('参数1','参数2'))

     1 import os
     2 import time
     3 from multiprocessing import Process
     4 
     5 def func(*args):
     6     print(args)
     7     time.sleep(3)
     8     print('子进程id:', os.getpid())
     9     print('子进程的父进程id:', os.getppid())
    10     print('子进程执行结束..')
    11 
    12 if __name__ == '__main__':
    13 
    14     p = Process(target=func,args=('星期一','星期二')) # 带参数函数注册进程
    15     p.start()
    16     print('主进程id:',os.getpid())
    17     print('主进程的代码执行完')
    带参数启动多进程

    2. 多进程常用的几个方法:

          1> p.join():设置主进程阻塞,等待子进程执行完毕后再继续执行主进程的代码,即主进程等待子进程执行完毕后,再执行自己后面的代码;

     1 import os
     2 import time
     3 from multiprocessing import Process
     4 
     5 def func(*args):
     6     print(args)
     7     time.sleep(3)
     8     print('子进程id:', os.getpid())
     9     print('子进程执行结束..')
    10 
    11 if __name__ == '__main__':
    12 
    13     p = Process(target=func,args=('星期一','星期二')) # 带参数函数注册进程
    14     p.start()
    15     print('主进程id:',os.getpid())
    16     p.join()   # 主进程的代码执行到这里时,等待子进程执行并结束后,再执行主进程以下的代码,将程序在此处由异步 改为 同步
    17     print('等子进程执行完毕后,才会执行这里的代码。')
    18     print('主进程的代码执行完')
    p.join方法

    3. 开启几十个进程后,各子进程异步执行,在主进程的某个代码处需要等待所有子进程执行完毕后,再继续执行后面的代码,实现如下

     1 import os
     2 import time
     3 from multiprocessing import Process
     4 
     5 def func(arg1,arg2):
     6     print('子进程id:', os.getpid())
     7     print("*" * arg1)
     8     time.sleep(5)
     9     print("*" * arg2)
    10 
    11 if __name__ == "__main__":
    12     p_list = []
    13     print('主进程id:', os.getpid())
    14     for i in range(1,5):
    15         p = Process(target=func, args=(2*i, 8*i))  # 带参数函数注册进程
    16         p_list.append(p)
    17         p.start()
    18         # p.join()  # 第一个子进程执行完毕后,再执行第二个子进程...直到最后一个子进程执行完毕后,再继续主进程后面的代码,即所有子进程和主进程都是同步的
    19     # p.join()  # 此时的p指的是for循环最后一个进程,所以这样只能达到最后一个进程与主进程在这之后由异步变成同步,而其他的子进程与主进程仍是异步
    20     [p.join() for p in p_list]  # 主进程要等待每一个异步执行的子进程执行完毕后,再继续执行后面代码,即每个异步子进程与主进程在这之后由异步变同步
    21     print('等子进程执行完毕后,才会执行这里的代码。')
    多进程由异步变同步

    4. 应用场景:同时写500个文件,待文件全部写完之后,展示所有的文件名

     1 import os
     2 from multiprocessing import Process
     3 
     4 def func(filename,content):
     5     with open(filename,'w') as fs:
     6         fs.write(content*'=')
     7 
     8 if __name__ == "__main__":
     9     p_list = []
    10     for i in range(1,5):
    11         p = Process(target=func,args=('info%s'%i, i))  # 多进程异步写4个文件,提升写文件的效率
    12         p_list.append(p)
    13         p.start()
    14     [i.join() for i in p_list]  # 等待所有文件写完成后,才能展示所有文件名
    15     # 向用户展示写入文件之后,文件夹中所有的文件名
    16     print([j for j in os.walk(r'D:old_boyDay36自己的')])
    多进程异步变同步的应用

    5. 另一种开启多进程的方法(面向对象) 

         1> 自定义一个类,继承Process类;

         2> 必须实现一个run()方法,即重写父类的run()方法,run方法的代码是在子进程中执行;

         3> 自定义的类若想传参数,初始化方法__init__记得一定要调用一下父类的__init__(),因为父类的初始化方法中还有很多其他属性是需要用到的;

     1 import os
     2 from multiprocessing import Process
     3 
     4 class MyProcess(Process):
     5     def __init__(self,arg1,arg2):
     6         super().__init__()  # 若不调用父类的初始化方法,执行会报错 AttributeError
     7         self.arg1 = arg1
     8         self.arg2 = arg2
     9 
    10     def run(self):
    11         print(self.pid)  # 查看进程id,和os.getpid()同功效
    12         print(self.name)
    13         print(os.getpid())
    14         print(self.arg1)
    15 
    16     def func(self):
    17         print(self.arg2)
    18 
    19 if __name__ == '__main__':
    20     print('主进程:',os.getppid())
    21     p1 = MyProcess(1,2)
    22     p1.start()  # start方法触发了调用run方法,而因为子类重写了run方法,即这里就是调用了MyProcess的run()
    23 
    24     p2 = MyProcess(3,4)
    25     p2.start()
    开启多进程(面向对象)

    6. 主进程和子进程的数据一般是完全隔离的,不共享的

     1 import os
     2 from multiprocessing import Process
     3 
     4 def func():
     5     global n
     6     n = 0
     7     print('子进程id:%s'%os.getpid(),n)
     8 
     9 if __name__ == "__main__":
    10     n = 200
    11     p = Process(target=func)
    12     p.start()
    13     p.join()
    14     print('主进程id: %s' %os.getpid(),n)
    15 # 从执行结果可以得出:主进程和子进程的数据一般是完全隔离的,不共享的;
    主子进程数据隔离

    7. 使用多进程实现socket服务端的并发效果

     1 import socket
     2 from multiprocessing import  Process
     3 
     4 # 一个socket服务端开启多个进程与多个客户端通信
     5 def server(conn):
     6     ret = '你好。。'.encode('utf-8')
     7     conn.send(ret)
     8     msg = conn.recv(1024).decode('utf-8')
     9     print(msg)
    10     conn.close()
    11 
    12 if __name__  == '__main__':
    13     sk = socket.socket()
    14     sk.bind(('127.0.0.1',8090))
    15     sk.listen()
    16     while True:
    17         conn,addr = sk.accept()
    18         p = Process(target=server,args=(conn,))
    19         p.start()
    20 
    21     sk.close()
    server端
     1 import socket
     2 
     3 sk = socket.socket()
     4 sk.connect(('127.0.0.1',8090))
     5 
     6 ret = sk.recv(1024).decode('utf-8')
     7 print(ret)
     8 msg = input('>>>>').encode('utf-8')
     9 sk.send(msg)
    10 
    11 sk.close()
    client端

    PS:1> 每一个程序重新运行时都是一个新的进程,那么只要我们把客户端运行设置为:重新打开一个平行的窗口运行而不是关闭当前窗口重新运行,就可实现多个客户端的效果

             2>pycharm中的设置方法如下:pycharm工具栏---->run---->Edit Configurations---->Allow parallal run(在右上角的位置),勾上它即代表重新运行时是开一个新的窗口

            3> 启动server端后,启动一个客户端,就会开启一个子进程与服务端通信,启动多个客户端(一般多个客户的代码是相同的)后,多个客户端与server端即建立了通信;

    8. 守护进程:主进程的代码执行结束,子进程的代码也应该执行结束,子进程应该随着主进程的结束而结束,这即为守护进程

          1> 一般默认情况下主进程是会等待子进程执行结束后,再结束主进程; 

          2> 而实际应用场景中,期望主进程的代码执行完成后,相关的子进程也结束;

          3> 没有进行设置时,子进程不会结束;

     1 import time
     2 from multiprocessing import Process
     3 
     4 def func(): # 向主进程报告自己的状态
     5     while True:
     6         time.sleep(0.5)
     7         print('我还活着。')
     8 
     9 if __name__ == "__main__":
    10     Process(target=func).start()
    11     i = 0
    12     while i < 2: 
    13         print('我是一个sokect server')
    14         time.sleep(5)
    15         i += 1
    16 
    17 # 从执行结果可见,主进程的逻辑代码执行完后,子进程一直在执行,主进程也一直在等待子进程执行结束
    18 # 而此时子进程不会自己结束 
    子进程没有被守护

         4> 设置子进程为守护进程:p.daemon = True,在p.start()前设置

     1 import time
     2 from multiprocessing import Process
     3 
     4 def func(): # 向主进程报告自己的状态
     5     while True:
     6         time.sleep(0.5)
     7         print('我还活着。')
     8 
     9 if __name__ == "__main__":
    10     p = Process(target=func)
    11     p.daemon = True  # 设置子进程为守护进程
    12     p.start()
    13     i = 0
    14     while i < 2:
    15         print('我是一个sokect server')
    16         time.sleep(5)
    17         i += 1
    子进程被守护

         5> 守护进程会随着主进程代码执行完毕而结束;

     1 def func1(): # 向主进程报告自己的状态
     2     while True:
     3         time.sleep(0.5)
     4         print('我还活着。')
     5 
     6 def func2():
     7     print('in func3 start..')
     8     time.sleep(9)
     9     print('in func3 finished..')
    10 
    11 if __name__ == "__main__":
    12     p1 = Process(target=func1)
    13     p1.daemon = True  # 设置子进程为守护进程
    14     p1.start()
    15     p2 = Process(target=func2)
    16     p2.start()
    17     i = 0
    18     while i < 2:
    19         print('我是一个sokect server')
    20         time.sleep(2)
    21         i += 1
    22 # 子进程1(守护进程)会随着主进程代码执行完毕而结束
    23 # 主进程代码执行完成后,子进程1执行结束,但是主进程仍在等待子进程2执行结束,因为子进程2没有被守护
    子进程的结束

         6> 判断子进程是否活着:p.is_alive(),返回True表示活着,返回False表示死了;

         7> p.terminate():结束进程,该方法执行后,进程不是立即就死了,而是有一个操作系统响应的过程;

         8> 获取进程名字:p.name

         9> 获取进程id:p.pid

     1 def func1(): # 向主进程报告自己的状态
     2     while True:
     3         time.sleep(0.5)
     4         print('我还活着。')
     5 
     6 def func2():
     7     print('in func3 start..')
     8     time.sleep(9)
     9     print('in func3 finished..')
    10 
    11 if __name__ == "__main__":
    12     p1 = Process(target=func1)
    13     p1.daemon = True  # 设置子进程为守护进程
    14     p1.start()
    15     p2 = Process(target=func2)
    16     p2.start()
    17     p2.terminate()  # 结束一个子进程
    18     print(p2.is_alive())  # 结果为True,因为操作系统回收p2进程没有那么快
    19     time.sleep(1)
    20     print(p2.is_alive())  # 判断子进程是否活着
    21     print(p2.name)  # 当前进程的名字
    进程的方法
  • 相关阅读:
    快速入门系列--GIT版本控制工具
    快速入门系列--NOSQL--05Redis也木有那么“高富帅”
    apt下载open-jdk8报错add-apt-repository: command not found
    jenkins-参数化构建(三)插件:Git Parameter
    jenkins-参数化构建(二)插件:Extended Choice Parameter
    jenkins-参数化构建(一)
    Jenkins-权限管理
    redis安装
    elk-图形化展示(八)
    elk-(七)
  • 原文地址:https://www.cnblogs.com/quiet-sun/p/14377019.html
Copyright © 2011-2022 走看看