• Python进程-实现


    fork介绍

    Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

    子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。

    Python的os模块封装了常见的系统调用

    import os
    
    if __name__ == '__main__':
    
        print('进程 (%s) start...' % os.getpid())
        pid = os.fork()
        # time.sleep(10)
        if pid == 0:  # 子进程fork()返回0
            print("子进程{},父进程{}".format(os.getpid(), os.getppid()))
        else:  # 父进程fork返回子进程的id
            print("父进程{},子进程{}".format(os.getpid(), pid))
    
    --》》结果
    进程 (3130) start...
    父进程3130,子进程3131
    子进程3131,父进程3130

    multiprocessing模块介绍

    python中的多线程无法利用CPU资源,在python中大部分计算密集型任务使用多进程。如果想要充分地使用多核CPU的资源(os.cpu_count()查看)

    python中提供了非常好的多进程包multiprocessing。

    multiprocessing模块用来开启子进程,并在子进程中执行功能(函数),该模块与多线程模块threading的编程接口类似。

    multiprocessing的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

     计算密集型任务:如金融分析,科学计算

    注意

    记住,进程的执行是有操作系统调度的,python执行进程(start)只是向操作系统发信号,告诉操作系统,我要开辟一个进程,由操作系统调度执行。

    同理,python终止进程(terminate)只是向操作系统发信号,告诉操作系统,我要终止一个进程,而不会马上终止,由操作系统调度终止进程。

    Process类的介绍

    1.创建进程的类

    Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
    
    强调:
    1. 需要使用关键字的方式来指定参数
    2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

    2.参数介绍

    group参数未使用,值始终为None
    
    target表示调用对象,即子进程要执行的任务
    
    args表示调用对象的位置参数元组,args=(1,2,'al',)
    
    kwargs表示调用对象的字典,kwargs={'name':'al','age':18}
    
    name为子进程的名称

    3.方法介绍

    p.start():启动进程,并调用该子进程中的p.run() 
    p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
    
    p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。
    如果p还保存了一个锁那么也将不会被释放,进而导致死锁
    p.is_alive():如果p仍然运行,返回True
    
    p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,
    需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

    4.属性介绍

    p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
    
    p.name:进程的名称
    
    p.pid:进程的pid
    
    p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
    
    p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,
    这类连接只有在具有相同的身份验证键时才能成功(了解即可)

    Process类的使用

    注意:在windows中Process()必须放到# if __name__ == '__main__':下

    开一个进程和主进程是并发的关系,我start一下就是先告诉操作系统我要开一个进程
    ,然而它不会等待,他会去执行下面的代码,完了他把进程开始后,就开始执行了

    # window创造进程相当于导入,会无线递归创建
    # Linux 是把父进程拷贝到子进程
    import multiprocessing
    import time
    import threading
    
    print('main process start1')
    def func():
        print('subprocess start',time.asctime(time.localtime(time.time())))
        time.sleep(3)
        print('subprocess end',time.asctime(time.localtime(time.time())))
    
    print('main process start2')
    p = multiprocessing.Process(target=func, name='1号')
    p.start()
    print('main process end', time.asctime(time.localtime(time.time())),multiprocessing.current_process())
    if __name__ == '__main__':
        pass
        # 默认所有进程结束后,程序才结束
    
    """
    linux 
    main process start1
    main process start2
    main process end Fri Mar 23 00:20:29 2018 <_MainProcess(MainProcess, started)>
    subprocess start Fri Mar 23 00:20:29 2018
    subprocess end Fri Mar 23 00:20:32 2018
    
    """
    
    """
    windows
    Make sure that the main module can be safely 
    imported by a new Python interpreter without causing unintended 
    side effects (such a starting a new process)."
    
    main process start1 
    main process start2
    main process end Fri Mar 23 00:23:50 2018 <_MainProcess(MainProcess, started)>
    main process start1 #相当于导入一次该程序,在main函数之前调用进程,会造成无限循环输出导致报错
    subprocess start Fri Mar 23 00:23:50 2018
    subprocess end Fri Mar 23 00:23:53 2018
    
    """

     strat():方法的功能

      1.开启进程
      2.执行功能

    开启进程方法一

    import time
    import multiprocessing
    # import threading
    
    def func():
        i = 0
        for _ in range(10000000):
            i += 1
        return  True
    
    def main():
        start = time.time()
        p = multiprocessing.Process(target=func)  # 创建一个子进程
        p1 = multiprocessing.Process(target=func)
        p.start()
        p1.start()
        # p = threading.Thread(target=func)
        # p.start()
        func()
        end = time.time()
        print(end - start)
    
    if __name__ == '__main__':
        main()

    开启进程方法二

    from multiprocessing import Process
    import time
    import random
    import os
    class pro(Process):
        def __init__(self,name):
            super().__init__() # 必须继承父类的一些属性
            self.name = name
        def run(self):  # 必须得实现一个run方法
            print('%s is work,父进程%s,当前进程%s'%(self.name,os.getppid(),os.getpid()))
            time.sleep(1)
            print('%s is work end'%self.name)
    if __name__ =='__main__':
        p1 = pro('al')
        p2 = pro('b1')
        p3 = pro('c1')
        p1.start()
        p2.start()
        p3.start()
        print('主进程',os.getpid())
    
    -》》输出
    主进程 9116
    b1 is work,父进程9116,当前进程4316
    al is work,父进程9116,当前进程6664
    c1 is work,父进程9116,当前进程10132
    b1 is work end
    al is work end
    c1 is work end

    使用daemon

    1. 守护进程会在主进程代码执行结束后就终止
    from multiprocessing import Process
    import time
    import random
    import os
    class My_Process(Process):
        def __init__(self,name):
            super().__init__() # 必须继承父类的一些属性
            self.name = name
    
        def run(self):  # 必须得实现一个run方法
            time.sleep(5)
            print('%s is work end'%self.name)
    
    if __name__ =='__main__':
        start_time = time.time()
        print("process start")
        for i in range(5):
            t = My_Process('Process%s' % i)
            # t.daemon = True
            t.start()
        time.sleep(3)
        print("process end")
        print(time.time() - start_time)
    
    """
     t.daemon = False
    process start
    process end  #主进程运行完毕后,程序等待子进程运行完成后结束
    0.020070791244506836
    Process0 is work end
    Process2 is work end
    Process3 is work end
    Process4 is work end
    Process1 is work end
    
    Process finished with exit code 0
    """
    
    
    """
     t.daemon = True
    process start
    process end   #主进程运行完毕后,守护进程结束
    3.014104127883911
    
    Process finished with exit code 0
    """

    2. 守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

    from multiprocessing import Process
    import time
    import random
    
    def task(name):
        print('%s is start' %name)
        time.sleep(random.randrange(1,3))
        print('%s is end' %name)
        p = Process(target=time.sleep, args=(3,)) #在守护进程里面开子进程报错
        p.start()
    
    
    if __name__ == '__main__':
        p=Process(target=task,args=('egon',))
        p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
    
        p.start()
        p.join()
        print('主') #只要终端打印出这一行内容,那么守护进程p也就跟着结束掉了
    -----------
    
    egon is start
    egon is end
    Process Process-1:
    Traceback (most recent call last):
      File "C:Program FilesPython36libmultiprocessingprocess.py", line 249, in _bootstrap
        self.run()
      File "C:Program FilesPython36libmultiprocessingprocess.py", line 93, in run
        self._target(*self._args, **self._kwargs)
      File "C:UsersjingjingPycharmProjectspy3Project路飞第四模块课件1网络编程进阶1 多进程5 守护进程.py", line 55, in task
        p.start()
      File "C:Program FilesPython36libmultiprocessingprocess.py", line 103, in start
        'daemonic processes are not allowed to have children'
    AssertionError: daemonic processes are not allowed to have children
    主
    

    思考下列代码的执行结果有可能有哪些情况?为什么?

    from multiprocessing import Process
    
    import time
    def foo():
        print(123)
        time.sleep(1)
        print("end123")
    
    def bar():
        print(456)
        time.sleep(3)
        print("end456")
    
    if __name__ == '__main__':
        p1=Process(target=foo)
        p2=Process(target=bar)
    
        p1.daemon=True
        p1.start()
        p2.start()
        print("main-------")
    
    
    -----输出
    main-------
    456
    end456
    当输出main之后,守护进程就结束了
    

      

    使用terminate

    import multiprocessing
    import time
    import threading
    
    
    def func():
        print('subprocess start',time.asctime(time.localtime(time.time())))
        time.sleep(3)
        print('subprocess end',time.asctime(time.localtime(time.time())))
    
    if __name__ == '__main__':
        p = multiprocessing.Process(target=func, name='1号')
        p.start()
        p.terminate() # 终止进程
        time.sleep(5)
        print(p.is_alive()) # 判断这个进程是否存在
        # 默认所有进程结束后,程序才结束
        print('main process end', time.asctime(time.localtime(time.time())), multiprocessing.current_process())
    
    -》》》输出
    """ False 终止进程后is_alive()返回False,没有执行print('subprocess s…… main process end Fri Mar 23 17:22:57 2018 <_MainProcess(MainProcess, started)> """

    使用join

    import multiprocessing
    import time
    import threading
    
    
    def func():
        print('subprocess start',time.asctime(time.localtime(time.time())))
        time.sleep(3)
        print('subprocess end',time.asctime(time.localtime(time.time())))
    
    if __name__ == '__main__':
        p = multiprocessing.Process(target=func, name='1号')
        p.start()
        p.join() # 等待子进程完成后,结束主线程
        # 默认所有进程结束后,程序才结束
        print('main process end', time.asctime(time.localtime(time.time())), multiprocessing.current_process())
    
    """
    不使用join
    # 主线程调用子线程后直接结束,然后子线程再结束
    main process end Fri Mar 23 17:34:01 2018 <_MainProcess(MainProcess, started)>
    subprocess start Fri Mar 23 17:34:01 2018
    subprocess end Fri Mar 23 17:34:04 2018
    """
    
    """
    使用join
    subprocess start Fri Mar 23 17:30:20 2018
    subprocess end Fri Mar 23 17:30:23 2018
    # 等待子进程完成后,结束主线程
    main process end Fri Mar 23 17:30:23 2018 <_MainProcess(MainProcess, started)>
    """

     join用法考题

    类似于单进程

    from multiprocessing import Process
    import time
    
    
    def task(n, t):
        time.sleep(t)
        print('-------->%s' %n)
    
    if __name__ == '__main__':
        p1=Process(target=task,args=(1,5))
        p2=Process(target=task,args=(2,2))
        p3=Process(target=task,args=(3,1))
        start = time.time()
        p1.start()
        p1.join()
        p2.start()
        p2.join()
        p3.start()
        p3.join()
    
        print('-------->time', time.time() - start)
    
    ------------------输出-----相当于单进程,时间等于3个进程执行时间的相加
    -------->1
    -------->2
    -------->3
    -------->time 9.534545183181763
    

    类似于多进程 

    from multiprocessing import Process
    import time
    
    
    def task(n, t):
        time.sleep(t)
        print('-------->%s' %n)
    
    if __name__ == '__main__':
        p1=Process(target=task,args=(1,5))
        p2=Process(target=task,args=(2,2))
        p3=Process(target=task,args=(3,1))
        start = time.time()
        p_l = [p1,p2,p3]
        for p in p_l:
            p.start()
    
        for p in p_l:
            p.join()
    
        print('--------4 >time', time.time() - start)
    
    ---------------输出------------相当于多进程,执行时间等于最长进程的执行时间
    -------->3
    -------->2
    -------->1
    --------4 >time 5.624321699142456
    

      

    使用多进程实现并发的服务器

    服务器端

    import socket
    import multiprocessing
    server = socket.socket()
    server.bind(('127.0.0.1', 9988))
    server.listen(5)
    
    def read_msg(conn, addr):
        while True:
            try:
                data = conn.recv(1024)
                if data:  # 正常接收数据
                    print('收到{}:数据{}'.format(addr,data.decode()))
                    conn.send(data)
                else:  # 收到空消息,关闭
                    print('close:{}'.format(addr))
                    break
            except Exception as e:
                print(e)
                break
        conn.close()
    
    if __name__ == '__main__':
        while True:
            print('-------主进程,等待连接------')
            conn, addr = server.accept()
            print('创建一个新的进程,和客户端{}通信'.format(addr))
            client= multiprocessing.Process(target=read_msg, args=(conn, addr))
            # client = threading.Thread(target=readable, args=((conn, addr)))
            # p.start()
            client.start()
        server.close()

    客户端

    # 客户端
    import socket  # 导入socket模块
    
    socket_client = socket.socket() # 创建监听套接字
    socket_client.connect(('127.0.0.1', 9988))  # 连接套接字 ,要连接的IP与端口
    
    while 1:
           cmd = input("Please input cmd:")   # 与人交互,输入命令
           if not cmd: continue
           elif cmd == 'q':break
           socket_client.send(cmd.encode('utf-8'))     # 把命令发送给服务端
           data = socket_client.recv(1024)
           print('recv',data)
    
    socket_client.close()

     练习题

    from multiprocessing import Process
    
    n=100 #在windows系统中应该把全局变量定义在if __name__ == '__main__'之上就可以了
    
    def work():
        global n
        n=0
        print('子进程内: ',n)
    
    
    if __name__ == '__main__':
        p=Process(target=work)
        p.start()
        print('主进程内: ',n)
    
    进程之间的内存空间是共享的还是隔离的?上述代码的执行结果是什么?
    进程之间的内存空间是隔离的
    执行结果:
    主进程内:  100
    子进程内:  0
    

    改写下列程序,分别别实现下述打印效果

    from multiprocessing import Process
    import time
    import random
    
    def task(n):
        time.sleep(random.randint(1,3))
        print('-------->%s' %n)
    
    if __name__ == '__main__':
        p1=Process(target=task,args=(1,))
        p2=Process(target=task,args=(2,))
        p3=Process(target=task,args=(3,))
    
        p1.start()
        p2.start()
        p3.start()
    
        print('-------->4')
    

    效果一:保证最先输出-------->4

    from multiprocessing import Process
    import time
    import random
    
    def task(n):
        time.sleep(random.randint(1,3))
        print('-------->%s' %n)
    
    if __name__ == '__main__':
        p1=Process(target=task,args=(1,))
        p2=Process(target=task,args=(2,))
        p3=Process(target=task,args=(3,))
    
        p1.start()
        p2.start()
        p3.start()
    
        print('-------->4')
    
    ----------输出
    -------->4
    -------->1
    -------->3
    -------->2
    

      

    效果二:保证最后输出-------->4

    from multiprocessing import Process
    import time
    import random
    
    def task(n):
        time.sleep(random.randint(1,3))
        print('-------->%s' %n)
    
    if __name__ == '__main__':
        p1=Process(target=task,args=(1,))
        p2=Process(target=task,args=(2,))
        p3=Process(target=task,args=(3,))
    
        p1.start()
        p2.start()
        p3.start()
    
        p1.join()
        p2.join()
        p3.join()
        print('-------->4')
    ----------------------------输出
    -------->1
    -------->3
    -------->2
    -------->4
    

      

    效果三:保证按顺序输出

    from multiprocessing import Process
    import time
    import random
    
    def task(n):
        time.sleep(random.randint(1,3))
        print('-------->%s' %n)
    
    if __name__ == '__main__':
        p1=Process(target=task,args=(1,))
        p2=Process(target=task,args=(2,))
        p3=Process(target=task,args=(3,))
    
        p1.start()
        p1.join()
        p2.start()
        p2.join()
        p3.start()
        p3.join()
    
    
        print('-------->4')
    
    -------------------------输出
    -------->1
    -------->2
    -------->3
    -------->4
    

    2、判断上述三种效果,哪种属于并发,哪种属于串行?

    第一种和第二种属于并发,最后一种属于并行

  • 相关阅读:
    AOP 相关包
    Dubbo学习(一) Dubbo原理浅析
    maven 三个仓库表
    关于servlet中doGet和doPost乱码再一次理解
    关于对String中intern方法的理解
    模拟文件上传(五):为文件添加描述信息
    模拟文件上传(四):对于前面三版中一些出错细节进行处理
    对于模拟文件上传(三)中,批量上传,传空值抛异常前台约束实现
    模拟文件上传(三):使用apache fileupload组件进行文件批量上传
    模拟文件上传(二):使用apache fileupload组件进行文件上传
  • 原文地址:https://www.cnblogs.com/xiao-apple36/p/8624924.html
Copyright © 2020-2023  润新知