• Python 进程(process)


    1. 进程

    1.1 进程的创建 fork

    • 正在运行着的代码,就称为进程
    # 示例:
    import os
    
    # 注意: fork 函数,只在 Unix/Linux/Mac 上运行, windows 不可以
    pid = os.fork()
    print(pid)
    if pid == 0:
        # 子进程执行(pid==0)
        print("=== 子进程 === %d %d" % (os.getpid(),os.getppid()))
    else:
        # 主(父)进程执行(pid>0)
        print("=== 父进程 ===%d" % os.getpid())
    

    1.2 全局变量在进程中不共享

    # 示例:
    import os
    import time
    
    g_num = 100
    
    ret = os.fork()
    if ret == 0:
        print("=== process 1 ===")
        g_num += 1
        print("=== process 1  g_num = %d===" % g_num)
    else:
        time.sleep(3)
        print("=== process 2 ===")
        print("=== process 2 g_num = %d ===" % g_num)
    
    # 输出:
    === process 1 ===
    === process 1  g_num = 101 ===
    === process 2 ===
    === process 2  g_num = 100 ===
    

    1.3 多次fork

    # 示例:
    import os
    
    ret = os.fork()
    if ret == 0:
        print("=== 1 ===")
    else:
        print("=== 2 ===")
    
    ret = os.fork()
    if ret == 0:
        print("=== 3 ===")
    else:
        print("=== 4 ===")
    
    # 输出:
    === 2 ===
    === 4 ===
    === 1 ===
    === 3 ===
    === 4 ===
    === 3 ===
    

    1.4 Process 创建子进程

    # 示例
    from multiprocessing import Process
    import os
    
    # 子进程要执行的代码
    def run_proc(name):
        print('子进程运行中, name=%s, pid=%d...' % (name, os.getpid()))
    
    
    if __name__=='__main__':
        print('父进程 %d.' % os.getpid())
        p = Process(target=run_proc, args=('test',))
        print('子进程将要执行')
        p.start()   # 创建子进程
        p.join()    # 等到子进程实例(p)执行结束后,才执行后面的代码
        print('子进程已结束')
    

    1.5 Process 的子类

    # 示例:
    from multiprocessing import Process
    import time
    import os
    
    # 继承Process类
    class Process_Class(Process):
        # 因为Process类本身也有 __init__ 方法,这个类相当于重写了这个方法;
        # 但这样就会带来一个问题,我们并没有完全的初始化一个 Process 类, 所以就不能使用从这个类继承的一些方法
        # 最好的方法就是将继承类本身传递给 Process.__init__ 方法, 完成这些初始化操作
        def __init__(self, interval):
            # super(Process_Class, self).__init__()
            Process.__init__(self)
            self.interval = interval
    
        # 重写Process类的run()方法
        def run(self):
            print("子进程(%s) 开始执行, 父进程为 (%s)" % (os.getpid(), os.getppid()))
            t_start = time.time()
            time.sleep(self.interval)
            t_stop = time.time()
            print("(%s)执行结束, 耗时%0.2f秒" % (os.getpid(), t_stop-t_start))
    
    if __name__=="__main__":
        t_start = time.time()
        print("当前进程(%s)" % os.getpid())
        p1 = Process_Class(2)
        # 对一个不包含target属性的Process类执行start()方法,就会运行这个类中的 run() 方法
        p1.start()
        p1.join()
        t_stop = time.time()
        print("(%s)执行结束, 耗时%0.2f" % (os.getpid(), t_stop-t_start))
    

    1.6 进程池 Pool(非阻塞方式)

    # 示例:
    from multiprocessing import Pool
    import os, time, random
    
    def worker(msg):
        t_start = time.time()
        print("%s开始执行, 进程号为%d" % (msg, os.getpid()))
        # random.random()随机生成0~1之间的浮点数
        time.sleep(random.random()*2)
        t_stop = time.time()
        print(msg, "执行完毕, 耗时%0.2f" % (t_stop-t_start))
    
    po = Pool(3)  # 定义一个进程池, 最大进程数 3
    for i in range(0, 10):
        # Pool.apply_async(要调用的目标,(传递给目标的参数元组,))
        # 每次循环将会用空闲出来的子进程去调用目标
        po.apply_async(worker,(i,))
    
    print("=== start ===")
    po.close()  # 关闭进程池,关闭后po不再接收新的请求
    po.join()   # 等待po中所有子进程执行完成, 必须放在close语句之后
    print("=== close ===")
    

    1.7 apply 阻塞方式添加任务

    # 示例:
    from multiprocessing import Pool
    import os, time, random
    
    def worker(msg):
        t_start = time.time()
        print("%s开始执行, 进程号为%d" % (msg, os.getpid()))
        # random.random()随机生成0~1之间的浮点数
        time.sleep(random.random()*2)
        t_stop = time.time()
        print(msg, "执行完毕, 耗时%0.2f" % (t_stop-t_start))
    
    po = Pool(3)  # 定义一个进程池, 最大进程数 3
    for i in range(0, 10):
        po.apply(worker, (i,))
    
    print("=== start ===")
    po.close()
    po.join()
    print("=== close ===")
    

    1.8 进程间通信(Queue)

    # 示例一: Queue 存取数据
    from multiprocessing import Queue
    q=Queue(3)  # 初始化一个Queue对象,最多可接收三条put消息
    q.put("消息1")
    q.put("消息2")
    print(q.full())     # False
    q.put("消息3")
    print(q.full())     # True
    
    # 因为消息队列已满,下面的try会抛出异常,第一个try会等待2秒后再抛出异常,第二个try会立刻抛出异常
    try:
        q.put("消息4",True,2)
    except:
        print("消息队列已满,现有消息数量: %s" % q.qsize())
    
    try:
        q.put_nowait("消息4")
    except:
        print("消息队列已满,现有消息数量: %s" % q.qsize())
    
    # 推荐的方式: 先判断消息队列是否已满, 再写入
    if not q.full():
        q.put_nowait("消息4")
    
    # 读取消息时, 先判断消息队列是否为空,再读取
    if not q.empty():
        for i in range(q.qsize()):
            print(q.get_nowait())
    
    
    
    # 示例二: 进程间通信
    # 在父进程中创建两个子进程,一个往Queue里写数据, 一个从Queue里读数据
    from multiprocessing import Process, Queue
    import os, time, random
    
    # 写数据进程执行代码
    def write(q):
        for value in ['A', 'B', 'C']:
            print('Put %s to queue...' % value)
            q.put(value)
            time.sleep(random.random())
    
    # 读数据进程执行代码
    def read(q):
        while True:
            if not q.empty():
                value = q.get(True)
                print('Get %s from queue.' % value)
                time.sleep(random.random())
            else:
                break
    
    
    if __name__=='__main__':
        # 父进程创建Queue,并传给各子进程
        q = Queue()
        pw = Process(target=write, args=(q,))
        pr = Process(target=read, args=(q,))
        # 启动子进程pw, 写入:
        pw.start()
        # 等待pw结束
        pw.join()
        # 启动子进程pr, 读取:
        pr.start()
        pr.join()
        # 所有子进程执行结束,输出
        print('所有数据都写入并读完')
    

    1.8.1 进程间通信(Pipe)

    # 示例:
    from multiprocessing import Process, Pipe
    
    def f(conn):
        conn.send([33, None, 'hello'])
        conn.close()
    
    if __name__ = '__main__':
        parent_conn, child_conn = Pipe()
        p = Process(target = f, args = (child_conn, ))
        p.start()
        print(parent_conn.recv())
        p.join()
    

    1.9 进程池中的Queue

    • 在进程池中,需要使用 multiprocessing.Manager()中的 Queue();而不是 multiprocessing.Queue()
    # 示例:
    from multiprocessing import Manager, Pool
    import os, time, random
    
    
    # 写数据进程执行代码
    def reader(q):
        print("reader启动(%s), 父进程为(%s)" % (os.getpid(), os.getppid()))
        for i in range(q.qsize()):
            print("reader从Queue获取到消息: %s" %q.get(True))
    
    # 读数据进程执行代码:
    def writer(q):
        print("writer启动(%s), 父进程为(%s)" % (os.getpid(), os.getppid()))
        for i in ['A', 'B', 'C']:
            q.put(i)
    
    if __name__=="__main__":
        print("(%s) start" % os.getpid())
        q=Manager().Queue()     # 使用Manager中的Queue来初始化
        po=Pool()
        # 使用阻塞模式创建进程,这样就不需要在reader中使用死循环了, 可以让writer执行完成后,再用reader读取
        po.apply(writer,(q,))
        po.apply(reader,(q,))
        po.close()
        po.join()
        print("(%s) End" % os.getpid())
    

    参考资料:

  • 相关阅读:
    新安装的Apache和php,测试可以解析phpinfo,但是无法打开drupal网站
    Drupal7安装注意事项
    drupal7 为视图添加 过滤标准 内容类型
    Drupal网站报错:PDOException: in lock_may_be_available()
    窗口聚合函数与分组聚合函数的异同
    Linux环境下段错误的产生原因及调试方法小结(转)
    gzip 所使用压缩算法的基本原理(选摘)
    InfluxDB使用纪录
    子网掩码解释(转)
    列存的压缩原理学习
  • 原文地址:https://www.cnblogs.com/linkworld/p/8546321.html
Copyright © 2020-2023  润新知