• python 进程(process)阻塞


    本文链接:https://www.cnblogs.com/tujia/p/13686684.html

    背景:来观察测试一下python 进程(process)的阻塞、普通进程和守护进程又有什么区别、进程池又是什么、进程池怎么异步提交任务等等

    一、公共代码

    首先先贴上一些公共代码,下面的例子都基于这份公共代码运行(注:替换xxx的内容)

    import time
    import multiprocessing
    
    
    def worker(name):
        print('%s: %s start...' % (time.strftime('%X'), name))
        time.sleep(2)
        print('%s: %s done.' % (time.strftime('%X'), name))
    
    
    def xxx():
        pass
    
    
    if __name__ == '__main__':
        xxx()

    二、单进程阻塞

    def 单进程阻塞():
        t = multiprocessing.Process(target=worker, args=('张三',))
        t.start()
        # 阻塞
        t.join()
        print('Finished')

    运行结果:

    解释:阻塞进程的情况下,程序会先等待进程任务执行完,再往下执行其他代码  

    三、单进程不阻塞

    def 单进程不阻塞():
        t = multiprocessing.Process(target=worker, args=('李四',))
        t.start()
        print('Finished')

    运行结果:

    解释:不阻塞进程的情况下,程序会直接往下走,进程任务是后完成的(因为我在进程任务里加了 sleep),类似于异步;同时,我们还可以发现,程序执行完最后一行代码之后,如果进程任务还没完成,程序是不会马上死掉的,还是会等进程任务执行完才会结束程序。

    四、多进程的错误阻塞

    def 多进程的错误阻塞():
        t1 = multiprocessing.Process(target=worker, args=('张三',))
        t1.start()
        t1.join()
        t2 = multiprocessing.Process(target=worker, args=('李四',))
        t2.start()
        t2.join()
        print('Finished')

    运行结果:

    解释:t1.join 直接阻塞了程序,t2还没start,t1.join阻塞程序直到t1的任务已完成。所以会看到 张三 done 之后,李四 才能 start

    五、多进程的正确阻塞

    def 多进程的正确阻塞():
        t1 = multiprocessing.Process(target=worker, args=('张三',))
        t2 = multiprocessing.Process(target=worker, args=('李四',))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print('Finished')

    运行结果:

      

    解释:需要将所有进程都start之后,才能阻塞(join);进程任务也不是按顺序执行和完成了,哪个先完成,得看哪个进程任务耗时少,也有可能会同时完成(并发) 

    按下面代码,修改一下worker函数,给李四加一下速,再执行一次看看:

    def worker(name):
        print('%s: %s start...' % (time.strftime('%X'), name))
        time.sleep(2 if name == '张三' else 1)
        print('%s: %s done.' % (time.strftime('%X'), name))

    注:多执行几次,你会发现,明明是t1.start() 再 t2.start(),为何回显总是 李四 start 在前。那是因为阻塞的进程,执行过程中是不会回显的,它需要执行完毕后才会一起回显。因为总是 李四 done 先,所以回显示就总是 李四 start 在前

    温馨提示:测试完记得把 worker 函数改回原来的样子,下面例子是以原版的 worker 为基础的

    六、多进程不阻塞

    def 多进程不阻塞():
        t1 = multiprocessing.Process(target=worker, args=('张三',))
        t2 = multiprocessing.Process(target=worker, args=('李四',))
        t1.start()
        t2.start()
        print('Finished')

    运行结果:

      

    解释: 参考上面单进程不阻塞↑,不阻塞的情况下,也是会等待全部进程任务执行完成才结束程序的。多进程有一定的并发现象

    七、守护进程阻塞

    def 守护进程阻塞():
        t1 = multiprocessing.Process(daemon=True, target=worker, args=('张三',))
        t2 = multiprocessing.Process(daemon=True, target=worker, args=('李四',))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print('Finished')

    运行结果:

    解释:这里看着上面的普通进程没有什么区别的,具体的区别看下面↓↓↓

    八、守护进程不阻塞

    def 守护进程不阻塞():
        t1 = multiprocessing.Process(daemon=True, target=worker, args=('张三',))
        t2 = multiprocessing.Process(daemon=True, target=worker, args=('李四',))
        t1.start()
        t2.start()
        print('Finished')

    运行结果:

    解释:进程任务都还没执行,主程序就执行完毕,结束了。这是守护进程(后台进程)的一个特点:不阻塞的情况下,后台进程(守护进程)会在主程序结束的时候自动死掉

    九、守护进程不阻塞但主进程比较晚结束

    def 守护进程不阻塞但主进程比较晚结束():
        t1 = multiprocessing.Process(daemon=True, target=worker, args=('张三',))
        t2 = multiprocessing.Process(daemon=True, target=worker, args=('李四',))
        t1.start()
        t2.start()
        time.sleep(5)
        print('Finished')

    运行结果:

    解释:这里的主进程并没有等子(守护)进程,只是主进程耗时比子进程还要久,子进程先执行完毕了 

    十、进程池阻塞

    def 进程池阻塞():
        with multiprocessing.Pool(processes=3) as pp:
            pp.apply(worker, ('张三',))
            pp.apply(worker, ('李四',))
            pp.close()
            pp.join()
        print('Finished')

    运行结果:

    解释:运行结果基本和“多进程的正确阻塞”基本一样,但又有一点不同,详情请看下面 “十二” 点~

    十一、进程池不阻塞

    def 进程池不阻塞():
        with multiprocessing.Pool(processes=3) as pp:
            pp.apply(worker, ('张三',))
            pp.apply(worker, ('李四',))
            pp.close()
        print('Finished')

    运行结果:

    解释:这不阻塞的效果感觉和阻塞的效果并没有什么区别

    十二、进程池的奇怪现象

    认真观察一下“十、进程池阻塞”和“十一、进程池不阻塞”,还有一个现象,不管是阻塞还是不阻塞,就上面的例子而言,李四居然要等张三done之后才能start,它们不应该同时start,同时done的吗??

    对比一下上面“五、多进程的正确阻塞”的运行结果 和 “十一、进程池不阻塞”的结果:

            与        

    解释:普通的多进程 start 是一起的(并发,单任务不阻塞),done的话就看任务的实际耗时。进程池的话,使用apply添加任务的时候,会自动阻塞任务,一个任务完成,再才执行下一个apply的任务。只想阻塞进程池,不要阻塞单任务的话,可以使用 apply_async 方法,详情请看下面↓↓↓

    十三、进程池异步阻塞

    def 进程池异步阻塞():
        with multiprocessing.Pool(processes=3) as pp:
            pp.apply_async(worker, ('张三',))
            pp.apply_async(worker, ('李四',))
            pp.close()
            pp.join()
        print('Finished')

    运行结果:

    解释,这下就真的和“多进程的正确阻塞”一样的,不会阻塞单任务

    十四、进程池异步不阻塞

    def 进程池异步不阻塞():
        with multiprocessing.Pool(processes=3) as pp:
            pp.apply_async(worker, ('张三',))
            pp.apply_async(worker, ('李四',))
            pp.close()
        print('Finished')

    运行结果:

    解释:异步不阻塞的话,就会和守护进程一样,主程序不会等待进程任务完成,会直接结束程序

    十五、进程池同步并发不阻塞

    上面说的apply是同步提交任务,apply_async是异步提交任务。apply是会阻塞的,顺序执行任务。那有没有同步又并发的方法呢?答案是有的,可以用map方法:

    def 进程池同步并发不阻塞():
        with multiprocessing.Pool(processes=3) as pp:
            pp.map(worker, ['张三', '李四'])
            pp.close()
        print('Finished')

    运行结果:

    解释:提供给map方法一个函数和参数列表,它会迭代参数列表,并发执行函数~

    需要注意的是,map和apply一样,是同步且阻塞的,多次调用map方法会和多次调用apply一样,会阻塞,需要等待第一次map任务执行完毕才会执行下面的map

    def 进程池同步并发阻塞():
        with multiprocessing.Pool(processes=3) as pp:
            pp.map(worker, ['张三', '李四'])
            pp.map(worker, ['王五', '赵六'])
            pp.close()
        print('Finished')

    运行结果:

    本文链接:https://www.cnblogs.com/tujia/p/13686684.html


    完。 

  • 相关阅读:
    进程和线程的区别?什么时候用进程?什么时候用线程?----看到好的复制到自己的园子里哈哈
    HTTPS详细讲解一篇就够了
    MySQL存储过程
    Spring注入全局的HttpServletRequest
    Java进阶必备
    Java8新特性
    java.time包常用类API学习记录
    Maven常用插件
    maven-dependency-versions-check-plugin, Maven 插件查找依赖版本冲突
    Jackson自定义注解
  • 原文地址:https://www.cnblogs.com/tujia/p/13686684.html
Copyright © 2020-2023  润新知