zoukankan      html  css  js  c++  java
  • python-多任务编程02-进程(processing)

    进程与程序

    程序:例如xxx.py这是程序,是一个静态的

    进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。

     multiprocessing模块

     multiprocessing模块就是跨平台版本的多进程模块,提供了一个Process类来代表一个进程对象,这个对象可以理解为是一个独立的进程,可以执行另外的事情

    from multiprocessing import Process
    import time
    import os
    
    
    def dancing():
        print('开始跳舞,进程号:%d' % os.getpid())
        for i in range(5):
            print('正在跳舞:。。。。%d' % i)
            time.sleep(0.5)
        print('结束跳舞')
    
    
    def singing():
        print('开始唱歌,进程号:%d' % os.getpid())
        for i in range(5):
            print('正在唱歌:。。。。%d' % i)
            time.sleep(0.5)
        print('结束唱歌')
    
    
    if __name__ == '__main__':
        # 创建对象
        p1 = Process(target=dancing)
        p2 = Process(target=singing)
        # 调用进程
        p1.start()
        p2.start()

    windows中可能多进程无效

    多进程在window10下的部分IDE中运行无效,如在sublime中运行结果还是并行的

    而在安装python后自带的IDLE中运行,也是无效的

     

     

     而只有在cmd终端运行时并行才有效果

     

     给进程传递参数

    from multiprocessing import Process
    import time
    import os
    
    
    def dancing(name, num, **kwargs):
        print('开始跳舞,进程号:%d, name=%s, num=%d, age=%d' % (os.getpid(), name, num, kwargs['age']))
        for i in range(num):
            print('%s正在跳舞:。。。。%d' % (name, i))
            time.sleep(0.5)
        print('结束跳舞')
    
    
    def singing(name, num, **kwargs):
        print('开始唱歌,进程号:%d, name=%s, num=%d, age=%d' % (os.getpid(), name, num, kwargs['age']))
        for i in range(num):
            print('%s正在唱歌:。。。。%d' % (name, i))
            time.sleep(0.5)
        print('结束唱歌')
    
    
    if __name__ == '__main__':
        # 创建对象
        p1 = Process(target=dancing, args=('xiaoming', 5), kwargs={'age': 10})
        p2 = Process(target=singing, args=('xiaohong', 10), kwargs={'age': 20})
        # 调用进程
        p1.start()
        p2.start()

    运行结果

    进程间通信

     使用multiprocessing自带的队列:Queue

    from multiprocessing import Process, Queue
    import time
    
    
    def put(queue):
        for i in [11, 22, 33, 44, 55]:
            print('put: %d' % i)
            queue.put(i)
            time.sleep(0.5)
    
    
    def read(queue):
        while not queue.empty():
            print('read: %d' % queue.get())
            time.sleep(0.5)
    
    
    if __name__ == '__main__':
        # 创建Queue对象
        queue = Queue()
        # 创建对象
        p1 = Process(target=put, args=(queue, ))
        p2 = Process(target=read, args=(queue, ))
        # 开始进程p1
        p1.start()
        # 等待p1运行完
        p1.join()
        print('queue是否满了:', queue.full(), ', 是否空了:', queue.empty())
        print('queue的大小为:%d' % queue.qsize())
        # 开始进程p2
        p2.start()
        # 等待p2运行完
        p2.join()
        print('queue是否满了:', queue.full(), ', 是否空了:', queue.empty())
        print('queue的大小为:%d' % queue.qsize())

    运行结果为:

    进程池

    当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。

    初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务,

    from multiprocessing import Pool
    import time
    import os
    import random
    
    
    def worker(msg):
        start_time = time.time()
        print('----------%s开始执行,进程号%d' % (msg, os.getpid()))
        time.sleep(random.random())
        end_time = time.time()
        print('----------%s执行结束, 耗时%0.2f' % (msg, (end_time - start_time)))
        # 异常测试
        print('捕获下面的print异常前')
        try:
            print(1 + 'end')
        except Exception as e:
            print('捕获到异常')
        print('不捕获下面的print异常')
        print(1 + 'end')
        print('不捕获异常后')
    
    
    def main():
        # 定义进程池,最大进程数为3
        pool = Pool(3)
        for i in range(1, 8):
            # 每次循环将会用空闲出来的子进程去调用目标
            pool.apply_async(worker, (i, ))
        pool.close()
        pool.join()
        # worker(0)
    
    
    if __name__ == '__main__':
        main()

    运行结果为:

     可以看到先立马将三个进程放入进程池中并开始执行,等到其中的某个进程运行结束后,再将新的进程放入进程池中

    在异常测试中发现,进程池中的方法,如果出现了异常,在运行时并不会直接报错,而只是是中断该进程,所以这里需要注意要手动将可能的异常进行捕获

    进程池中使用Queue

    如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:

    RuntimeError: Queue objects should only be shared between processes through inheritance.

    进程与线程对比

    定义的不同

    1. 进程是系统进行资源分配和调度的一个独立单位.
    2. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

    其他区别

    1. 一个程序至少有一个进程,一个进程至少有一个线程.
    2. 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
    3. 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率
    4. 线程不能够独立执行,必须依存在进程中
    5. 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
  • 相关阅读:
    Tensorflow中实现BN为什么需要加入这个额外依赖?见CS231N作业源码
    为何神经网络权重初始化要随机初始化,不能以0为初始化
    Batch Normalization&Dropout浅析
    Git版本回退和撤销修改的区别
    linux下安装git提示”无法打开锁文件 /var/lib/dpkg/lock
    数据特征选择法
    深度学习笔记整理
    全面掌握IO(输入/输出流)
    startActivity时报错Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVI
    LitePal——Android数据库框架完整使用手册
  • 原文地址:https://www.cnblogs.com/gcxblogs/p/12934312.html
Copyright © 2011-2022 走看看