• python多进程


     

    进程概念:

    1、是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

    2、对于操作系统来说,一个任务就是一个进程,比方说打开浏览器就是启动一个浏览器的进程

    3、进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上

    进程和程序的区别

    程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念

    而进程是程序在处理机上的一次执行过程,它是一个动态的概念

    程序可以作为一种软件资料长期存在,而进程是有一定生命期的。

    程序是永久的,进程是暂时的

      

    进程并发和并行

    并发:如果系统只有一个CPU,实际就是交替执行任务,之后交替比较快

    是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行,是指系统具有处理多个任务的能力。黑线代表同一个cpu,红块代表处理任务

    并行:多核cpu.当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。简言之,是指系统具有同时处理多个任务的能力。 黑线表CPU,红色代表cpu

    进程优点

    稳定性高,一个进程山崩溃了,不会影响其他进程

    进程缺点

    开销比较大

    windows查看进程--任务管理

    启动进程的步骤

    1、引入进程包 multiprocessing

    2、编写函数

    3、创建启用进程

    linux 下可以使用fork函数创建进程。在windows系统multiprocessing模块

    linux是多任务系统

    Process 功能介绍

    Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)
    
    强调:
    1. 需要使用关键字的方式来指定参数
    2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
    
    参数介绍:
    1 group参数未使用,值始终为None
    2 target表示调用对象,即子进程要执行的任务
    3 args表示调用对象的位置参数元组,args=(1,2,'egon',)
    4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
    5 name为子进程的名称

    Process 方法介绍

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

    Process 属性介绍

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

    if __name__ == '__main__':
    p1 = Process(target=func,args=("1",))
    p1.start()
    #启多个进程
    from multiprocessing import Process
    def func(n):
    print(n)


    if __name__ == '__main__':
    plist=["p1","p2"]
    for p in plist:
    p = Process(target=func,args=("2",))
    p.start()
    #继承进程
    from multiprocessing import Process
    def func(n):
        print(n)
    
    class MyProcess(Process):
        def run(self):
            print("进程")
    
    if __name__ == '__main__':
        myprocess = MyProcess()
        myprocess.start()
    #启动多个进程
    import multiprocessing
    import time
    def func_a():
        print("进程func_a")
        time.sleep(0.5)
    
    def func_b():
        print("进程func_b")
        time.sleep(0.5)
    
    if __name__ == '__main__':
        p1 = multiprocessing.Process(target=func_a)
        p2 = multiprocessing.Process(target=func_b)
        p1.start()
        p2.start()
    #不加进程,会一直进行func_a 函数,不执行func_b()函数
    import multiprocessing
    import time
    def func_a():
        while True:
            print("进程func_a")
            time.sleep(0.5)
    
    def func_b():
        while True:
            print("进程func_b")
            time.sleep(0.5)
    
    if __name__ == '__main__':
        func_a()
        func_b()
    
    # 这样多进程就是打2次任务2,1次任务1
    import multiprocessing
    import time
    def func_a():
        while True:
            print("进程func_a")
            time.sleep(0.5)
    
    def func_b():
        while True:
            print("进程func_b")
            time.sleep(1)
    
    if __name__ == '__main__':
        p1=multiprocessing.Process(target=func_a)
        p2=multiprocessing.Process(target=func_b)
        p1.start()
        p2.start()

    区别主进程和子进程

    1、通过进程号判断主进程还是子进程

    2、debug的时候断点要加在子进程,如果在主进程是无法看到的子进程的代码

    os.getpid()  获取当前进程号  os.getppid()  获取当前父进程号

    import multiprocessing
    import time,os
    def func_a():
        while True:
            print("进程func_a",os.getpid(),'^^^^^^^^^^^^^^^^^^^^^^^',os.getppid())
            time.sleep(0.5)
    
    def func_b():
        while True:
            print("进程func_b",os.getpid(),'^^^^^^^^^^^^^^^^^^^^^^^',os.getppid())
            time.sleep(1)
    
    if __name__ == '__main__':
        print(os.getpid())
        p1=multiprocessing.Process(target=func_a,name='任务1')  #开始子进程
        p2=multiprocessing.Process(target=func_b,name='任务2') #开始子进程
        p1.start() #主进程启动子进程
        print(p1.name) #主进程
        p2.start() #主进程启动子进程
        print(p2.name)#主进程

     进程参数

    import multiprocessing
    import time,os
    def func_a(s,name):
        while True:
            print("进程func_a",os.getpid(),s,'^^^^^^^^^^^^^^^^^^^^^^^',os.getppid(),name)
            time.sleep(0.5)
    
    def func_b(s,name):
        while True:
            print("进程func_b",os.getpid(),s,'^^^^^^^^^^^^^^^^^^^^^^^',os.getppid(),name)
            time.sleep(1)
    
    if __name__ == '__main__':
        print(os.getpid())
        p1=multiprocessing.Process(target=func_a,name='任务1',args=(1,"aa"))  #开始子进程
        p2=multiprocessing.Process(target=func_b,name='任务2',args=(2,"bb")) #开始子进程
        p1.start() #主进程启动子进程
        print(p1.name) #主进程
        p2.start() #主进程启动子进程
        print(p2.name)#主进程
     1 #终止进程
     2 import multiprocessing
     3 import time,os
     4 def func_a(s,name):
     5     n=1
     6     while True:
     7         print("进程func_a",os.getpid(),s,'^^^^^^^^^^^^^^^^^^^^^^^',os.getppid(),name)
     8         time.sleep(0.5)
     9 
    10 def func_b(s,name):
    11     n=2
    12     while True:
    13         print("进程func_b",os.getpid(),s,'^^^^^^^^^^^^^^^^^^^^^^^',os.getppid(),name)
    14         time.sleep(1)
    15 
    16 number = 1
    17 if __name__ == '__main__':
    18     print(os.getpid())
    19     p1=multiprocessing.Process(target=func_a,name='任务1',args=(1,"aa"))  #开始子进程
    20     p2=multiprocessing.Process(target=func_b,name='任务2',args=(2,"bb")) #开始子进程
    21     p1.start() #主进程启动子进程
    22     print(p1.name) #主进程
    23     p2.start() #主进程启动子进程
    24     print(p2.name)#主进程
    25     # func_a()
    26     # func_b()
    27     while True:
    28         number +=1
    29         if number == 10:
    30             time.sleep(0.5)
    31             p1.terminate()  # 终止P1进程
    32             p2.terminate()  # 终止p2进程
    33             break
    34         else:
    35             print("number:",number)
    36     print("…………………………………………………………………………")
    #不加休眠,进程和顺序是无法控制
    #进程对全局变量操作是 子进程和主进程都可以拿到全局变量的值,做各个的更改。
    #m=2,全局变量与可变类型和不可变类型没有关系 import multiprocessing import time,os m=2 def func_a(s,name): global m while True: time.sleep(0.5) m+=1 print("进程func_a",m) def func_b(s,name): global m while True: time.sleep(1) m += 1 print("进程func_b",m) if __name__ == '__main__': p1=multiprocessing.Process(target=func_a,name='任务1',args=(1,"aa")) #开始子进程 p2=multiprocessing.Process(target=func_b,name='任务2',args=(2,"bb")) #开始子进程 p1.start() #主进程启动子进程 p2.start() #主进程启动子进程 while True: time.sleep(0.5) m+=1 print("主进程",m)

     

     进程共享变量value

    multiprocessing.Value(typecode_or_type, *args[, lock])

     字符串 

    from ctypes import c_char_p

    ss = Value(c_char_p, 'ss')

    ctype类型可从下表查阅

    #共享数字
    def func_a(name): name.value=10.88 print("进程func_b",name) if __name__ == '__main__': name=multiprocessing.Value("d",4.5) print("主线程",name.value) p1=multiprocessing.Process(target=func_a,args=(name,)) #开始子进程 p1.start() #主进程启动子进程 p1.join() print("主线程",name.value)

      

    #共享数组
    def func_a(name):
        name[2]=999
        print("进程func_b",name)
    
    if __name__ == '__main__':
        name=multiprocessing.Array("i",[1,2,3,4])
        print("主线程:在子进程之前",name[:])
        p1=multiprocessing.Process(target=func_a,args=(name,))  #开始子进程
        p1.start() #主进程启动子进程
        p1.join()
        print("主线程:在子进程之后",name[:])
    

      

    进程数据共享

    进程池Pool(5),所谓进程池,就是控制进程的数量

    • close()    关闭pool,使其不在接受新的任务。
    • terminate()    结束工作进程,不在处理未完成的任务。
    • join()    主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用。

     阻塞式和非阻塞式 

    -- 阻塞式 apply  apply(func[, args[, kwds]])是阻塞

    -- 阻塞进程 p = Pool(5) 进程池一共起5个进程,一个进程一个进程做任务。阻塞进程是进程1的任务1完成了,再做进程2的任务

    -- 非阻塞进程 p = Pool(5) 进程池一共起5个进程,5个进程共同做任务。进程1任务完成,会再进一个新任务。

    def func(n):
        print(n)
        time.sleep(2)
        print('end')
        return "done"+n
    
    if __name__ == '__main__':
        #阻塞进程
        p = Pool(5)
        for i in range(4):
            msg = "阻塞进程hello %d"  %(i)
            p.apply(func,(msg,))
        p.close() #添加任务结束
        p.join() #阻塞主进程,继续子进程任务。如果不阻塞的话,主进程结束,子进程就结束

    运行结果

    阻塞进程hello 0
    end
    阻塞进程hello 1
    end
    阻塞进程hello 2
    end
    阻塞进程hello 3
    end

    -- 非阻塞式 apply_async  apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞

    def func(n):
        print(n)
        time.sleep(2)
        print('end')
        return "done"+n
    if __name__ == '__main__':
        #非阻塞进程
        p = Pool(5)
        result = []
        for i in range(4):
            msg = "非阻塞进程hello %d"  %(i)
            result.append(p.apply_async(func,(msg,)))
      p.close()
      p.join()
      for res in result:
      print("::::",res.get()) 

    非阻塞进程hello 0
    非阻塞进程hello 1
    非阻塞进程hello 2
    非阻塞进程hello 3
    end
    end
    end
    end
    :::: done非阻塞进程hello 0
    :::: done非阻塞进程hello 1
    :::: done非阻塞进程hello 2
    :::: done非阻塞进程hello 3

    阻塞进程的回调函数,回调函数在爬虫中最常用。

    回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数

    我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。

    from  multiprocessing import Pool
    import time,random,os
    def func_a(task_name):
        print("开始做任务",task_name)
        start_time = time.time()
        time.sleep(random.uniform(1,3))
        end_time = time.time()
        print(end_time-start_time)
        m="任务名称",task_name,"任务用时",(end_time-start_time),"进程id",os.getpid()
        print(m)
        return m
    #回调函数
    container=[]
    def callback_fun(m):
        container.append(m)
    
    if __name__ == '__main__':
        pool=Pool(4)
        task_names=["吃饭","睡觉","挣钱","哄孩子","看电视","听音乐","写代码"]
        for task_name in task_names:
            pool.apply_async(func_a,args=(task_name,),callback=callback_fun)
        pool.close()
        pool.join()
        for i in container:
            print(i)
    

    进程通信

    from  multiprocessing import Process,Queue
    #不加join,边写边读。加join,写完再读
    def write_pro(q):
        print("开始写入线程…………")
        for i in range(1,20):
            #判断队列是否满,加while是不断放
            while not q.full():
                q.put(i,timeout=2)
                time.sleep(0.1)
                print("队列的长度write:", q.qsize())
    
    
    def read_pro(q):
        print("开始读取线程…………")
    
        # 判断队列是否为空,加while是不断取
        while not q.empty():
            # 获取没有timeout参数 block=False 与timeout一样
            try:
                time.sleep(0.1)
                print("从队列取出的值",q.get(timeout=5))
                print("队列的长度read:", q.qsize())
            except:
                print("全部保存完毕")
    
    if __name__ == '__main__':
        #定义进程的长度,队列只能放长度为4
        q = Queue(3)
    
        p1 = Process(target=write_pro,args=(q,))
        p2 = Process(target=read_pro, args=(q,))
    
        p1.start()
        # p1.join() #插队,优先写入
    
        p2.start()
        # p2.join() #插队,优先写入
    

     队列

        #定义队列的长度
        q = Queue(3)
        print("定义队列的长度",q.qsize())
        #放入数据
        q.put("a")
        print("放入数据之后队列的长度", q.qsize())
        #取出数据
        q.get()
        print("取出数据队列的长度", q.qsize())
        #如果队列为空,返回True, 反之False
        print(q.empty())
        #如果队列满了,返回True, 反之False
        print(q.full())
    

      进程同步和异步

      

    join是等待进程结束,那么我像下面这样写,进程不就又变成串行的了吗
    不是,p.join()是让谁等。

    进程守护:主进程创建子进程,然后将该进程设置成守护自己的进程,守护进程就好比崇祯皇帝身边的老太监,崇祯皇帝已死老太监就跟着殉葬了;

     关于守护进程需要强调两点:
        其一:守护进程会在主进程代码执行结束后就终止
        其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children
        如果我们有两个任务需要并发执行,那么开一个主进程和一个子进程分别去执行就ok了,如果子进程的任务在主进程任务结束后就没有存在的必要了,那么该子进程应该在开启前就被设置      成守护进程。主进程代码运行结束,守护进程随即终止;     

    from multiprocessing import Process
    import time
    import random
    def task(name):
        print('%s is piaoing' %name)
        time.sleep(random.randrange(1,3))
        print('%s is piao end' %name)
    if __name__ == '__main__':
        p=Process(target=task,args=('egon',))
        p.daemon=True #一定要在p.start()前设置,设置p为守护进程,禁止p创建子进程,并且父进程代码执行结束,p即终止运行
        p.start()
        print('主') #只要终端打印出这一行内容,那么守护进程p也就跟着结束掉了
    

       

    上班求生存,下班求发展
  • 相关阅读:
    7.29 H5学习笔记
    8.1H5学习笔记
    8.4 H5知识点总结
    8.15 CSS知识点6
    8.12 CSS知识点5
    HTTP协议简析(二)
    php实现二分查找法
    http协议简析(一)
    telnet客户端模拟浏览器发送请求
    导入txt文件到SQL SERVER 2008
  • 原文地址:https://www.cnblogs.com/ljf520hj/p/14942444.html
Copyright © 2020-2023  润新知