• 并发编程之多进程


    一 多进程

    我们今天主要是进程的创建:

    进程的创建分为四种:其中在进程中开启子进程是我们的重点。

       1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,
    运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)   
    2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)   3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)   4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)

      无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的:

      1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)

      2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。

    二  Process进程开启的两种方式:

    开启子进程方式一:
    from multiprocessing import Process
    import time
    def task(name):
        time.sleep(2)
        print('%s is running'%name)
    if __name__ == '__main__':
        t=Process(target=task,args=('feng',))
        t=Process(target=task,kwargs={'name':'feng'})#args与kwargs是一样的只是形式不同而已。
        t.start()###### 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,位子进程的数据初始化。
        print('zhu'.center(50,'*'))          
    运行结果为:

    ***********************zhu************************
    feng is running

    整个程序的运行其实就是,先定义一个函数task,然后运行主程序,在运行主程序的的过程创建一个子进程,子进程具体是由操作系统来创建的。而创建一个子程序所需要的时间远大于运行一行代码,所以首先打印出***********************zhu************************,然后子进程开始运行,输出feng is running

    方式二:
    from multiprocessing import Process
    import  time
    class MyProcess(Process):
        def __init__(self,name):
            super().__init__()
            self.name=name
        def run(self):       ######这里必须是一个run方法,自己定义一个类,继承父类Process,
            time.sleep(2)
    print('%s is running'%self.name)
    if __name__ == '__main__':
    t=MyProcess('feng')
    t.start() #t.start()调的就是run()
    print('zhu'.center(50,'='))
    运行结果为:

    =======================zhu========================
    feng is running

    整个程序的运行,先定义一个类。

    下面我们子进程与父进程的关系:

        1 在内存中进程之间是互相隔离的:

    from multiprocessing import Process
    import time
    x=1000
    def run(name):
        global x
        x=0
        time.sleep(2)
        print('%s is running'%name,x)
    if __name__ == '__main__':
        t=Process(target=run,args=('feng',))
        t.start()#在这里子进程启动,其实就是调用父进程中的run,执行,
        time.sleep(5)
        print(x)
    运行结果:

    feng is running 0
    1000

    x=1000,是定义阶段就确定的,所以主进程的x不会随着在子进程中的改变而改变,而如果我们在子进程中打印x,那么就是改变后的值。

    通过这个过程我们可以看出,子进程与父进程的内存空间是独立的。也就是说,子进程的改变不会影响父进程。父进程不会执行run内的代码。

         2 Process对象的join方法 :就是让父进程等子进程运行结束再运行。

    我们讲的jion的用法:
    from multiprocessing import Process
    import time
    x=1000
    def task():
        time.sleep(3)
        global  x
        x=0
        print('儿子结束了',x)
    
    if __name__ == '__main__':
        print(x)
        p=Process(target=task,)
        p.start()
        p.join()    ##让父亲在原地等。等到子进程运行结束后父进程才会继续运行。
        print(x)
    # 运行结果为:
    '''
    1000
    儿子结束了 0
    1000'''

      3  Process子进程实现并发:

    # from multiprocessing import Process
    # import time
    #
    # def task(n):
    #     print('%s is running'%n)
    # if __name__ == '__main__':
    #     for i in range(1,4):
    #         p=Process(target=task,args=(i,))
    #         p.start()
    #
    #     print('主'.center(20,'='))
    # # 输出结果为:
    # '''
    # =========主==========
    # 3 is running
    # 1 is running
    # 2 is running'''#为什么输出结果为无序的呢:那是因为start只是向操作系统发出请求,创建子进程,那么创建完子进程嗯么运行
    #这完全是由操作系统控制的了。

       4 join与并发:

    方式一:比较low的方式
    from
    multiprocessing import Process import time def task(n): print('%s is running'%n) time.sleep(3) 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('') # 运行结果为: ''' 2 is running 1 is running 3 is running
    方式二:使用循环:
    from multiprocessing import Process
    import time
    def task(n):
        print('%s is running'%n)
        time.sleep(3)

    if __name__ == '__main__':
    #     start_time=time.time()
    # p_list=[]
    # for i in range(1,4):
    # p=Process(target=task,args=(i,))
    # p_list.append(p)
    # p.start()
    # for p in p_list:
    # p.join()
    # print('主',time.time()-start_time)
    运行结果:
    # '''
    # 2 is running
    # 1 is running
    # 3 is running
    # 主 2.1594531536102295
    # '''

       5   Process进程对象方法:terminate,is_alive。

    进程对象的其他方法一:terminate,is_alive
    from multiprocessing import Process
    import time
    import random
    
    class Piao(Process):
        def __init__(self,name):
            self.name=name
            super().__init__()
    
        def run(self):
            print('%s is piaoing' %self.name)
            time.sleep(random.randrange(1,5))
            print('%s is piao end' %self.name)
    
    
    p1=Piao('egon1')
    p1.start()
    
    p1.terminate()#关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
    print(p1.is_alive()) #结果为True
    
    print('开始')
    print(p1.is_alive()) #结果为False

     6  查看进程id也就是pid

    # from multiprocessing import Process
    # import time,random
    # import os
    #
    # def task():
    #     time.sleep(2)
    #     print('me:%s,father:%s'%(os.getpid(),os.getppid()))
    # if __name__ == '__main__':
    #     p2=Process(target=task,)
    #     p2.start()
    #     # p2.join()
    #
    #     print(p2.name,p2.pid)
    #     print('主',os.getppid())
    print('主',os.getpid())#这个输出的结果是跟子进程的father是一样的。
    print('主',os.getppid())#而这个输出的结果为pycha的pid。

    # # 运行结果为: # ''' # Process-1 8200 # 主 3428 # me:8200,father:4940'''

    僵尸进程:子进程死了,父进程还在(父进程大量造子进程,导致大量pid被占用),僵尸进程是有害的。

    孤儿进程:父进程先结束,子进程由init来管理子进程,孤儿进程是无害的。

  • 相关阅读:
    数据库设计
    java 的继承,深入理解
    ant 使用笔记
    Effective C++ 精要(第七部分:模板与泛型编程)
    Effective C++ 精要(第八部分:定制new和delete)
    求数组的子数组之和的最大值
    Effective C++ 精要(第四部分:设计与声明)
    STL的容器中存储对象和指针的利和弊
    (zz)Why Memory Barrier
    理解smart pointer之二:如何实现一个smart pointer
  • 原文地址:https://www.cnblogs.com/zhangsanfeng/p/8931226.html
Copyright © 2020-2023  润新知