zoukankan      html  css  js  c++  java
  • 多进程

    一、多进程

    1.1、概念

      进程是程序在计算机上的一次执行活动。当你运行一个程序,你就启动了一个进程。显然,程序是死的(静态的),进程是活的(动态的)。进程可以分为系统进程和用户进程。凡是用于完成操作系统的各种功能的进程就是系统进程,它们就是处于运行状态下的操作系统本身;用户进程就不必我多讲了吧,所有由你启动的进程都是用户进程。进程是操作系统进行资源分配的单位。它的思想简单介绍如下:

    在操作系统的管理下,所有正在运行的进程轮流使用CPU,每个进程允许占用CPU的时间非常短(比如10毫秒),这样用户根本感觉不出来CPU是在轮流为多个进程服务,就好象所有的进程都在不间断地运行一样。但实际上在任何一个时间内有且仅有一个进程占有CPU。

    shell中使用多进程的类型:

    #!/bin/bash

    testsleep(){
        echo "start sleep"
        sleep 5
        echo "end sleep"
    }
    echo "start main"
    testsleep &            #&后台运行的模式就是使用了多进程的理念
    echo "end main"

    1.2、多进程和多线程的区别:

    • 多进程使用的是cpu的多个核,适合运算密集型
    • 多线程使用的是cpu的一个核,适合io密集型

    1.3、组件

    Python提供了非常好用的多进程包,multiprocessing,我们在使用的时候,只需要导入该模块就可以了。Multiprocessing支持子进程,通信,共享数据,执行不同形式的同步,提供了Process,Pipe, Lock等组件

    1.4、示例:

    import multiprocessing
    import time

    def worker(args, interval):
    print("start worker {0}".format(args))
    time.sleep(interval)
    print("end worker {0}".format(args))

    def main():
    print("start main")
    p1 = multiprocessing.Process(target=worker, args=(1, 1))
    p2 = multiprocessing.Process(target=worker, args=(2, 2))
    p3 = multiprocessing.Process(target=worker, args=(3, 3))
    p1.start()
    p2.start()
    p3.start()
    print("end main")

    if __name__ == '__main__':
    main()

    # p = multiprocessing.Process(target=, args=)
    # target 指定的是当进程执行时,需要执行的函数
    # args 是当进程执行时,需要给函数传入的参数
    # 注意: args必须是一个tuple, 特别是当函数需要传入一个参数时 (1,)
    # p 代表的是一个多进程,
    # p.is_alive() 判断进程是否存活
    # p.run() 启动进程
    # p.start() 启动进程,他会自动调用run方法,推荐使用start
    # p.join(timeout) 等待子进程结束或者到超时时间
    # p.terminate() 强制子进程退出
    # p.name 进程的名字
    # p.pid 进程的pid

    1.5、示例:

    import multiprocessing
    import time

    def worker(args, interval):
    print("start worker {0}".format(args))
    time.sleep(interval)
    print("end worker {0}".format(args))

    def main():
    print("start main")
    p1 = multiprocessing.Process(target=worker, args=(1, 1))
    p2 = multiprocessing.Process(target=worker, args=(2, 2))
    p3 = multiprocessing.Process(target=worker, args=(3, 3))
    p1.start()
    p1.join(timeout=0.5)
    p2.start()
    p3.start()
    print("the number of CPU is: {0}".format(multiprocessing.cpu_count()))
    for p in multiprocessing.active_children(): #打印存活的子进程
    print("The name of active children is: {0}, pid is: {1} is alive".format(p.name, p.pid))
    print("end main")

    if __name__ == '__main__':
    main()

    1.6、Lock组件

    当我们用多进程来读写文件的时候,如果一个进程是写文件,一个进程是读文件,如果两个文件同时进行,肯定是不行的,必须是文件写结束以后,才可以进行读操作。或者是多个进程在共享一些资源的时候,同时只能有一个进程进行访问,那就要有一个锁机制进行控制。

    需求:
    一个进程写入一个文件,一个进程追加文件,一个进程读文件,同时启动起来
    我们可以通过进程的join()方法来实现,但是为了学习Lock,用Lock来实现。
    先看不加锁程序,在看加锁程序,最后比较两个程序的区别

    示例:

    import time
    import multiprocessing

    def add1(lock, value, number):
    with lock: #这里是第一种调用锁的方法,好处是能自动释放锁
    print("start add1 number= {0}".format(number))
    for i in range(1, 5):
    number += value
    time.sleep(0.3)
    print("number = {0}".format(number))

    def add3(lock, value, number):
    lock.acquire() #这里是第二种调用锁的方法,在下面需要有释放锁的操作
    print("start add3 number= {0}".format(number))
    try:
    for i in range(1, 5):
    number += value
    time.sleep(0.3)
    print("number = {0}".format(number))
    except Exception as e:
    raise e
    finally:
    lock.release()


    if __name__ == '__main__':
    print("start main")
    number = 0
    lock = multiprocessing.Lock() #这里创建了锁的机制,目的是为了避免进程间无序执行
    p1 = multiprocessing.Process(target=add1, args=(lock, 1, number))
    p3 = multiprocessing.Process(target=add3, args=(lock, 3, number))
    p1.start()
    p3.start()
    print("end main")

    1.7、共享内存

    python的multiprocessing模块也给我们提供了共享内存的操作

    一般的变量在进程之间是没法进行通讯的,multiprocessing给我们提供了Value和Array模块,他们可以在不通的进程中共同使用

    示例:

    import multiprocessing
    from multiprocessing import Value, Array, Manager

    def add1(value, number):
    print("start add1 number= {0}".format(number.value))
    for i in range(1, 5):
    number.value += value
    print("number = {0}".format(number.value))

    def add3(value, number):
    print("start add3 number= {0}".format(number.value))
    try:
    for i in range(1, 5):
    number.value += value
    print("number = {0}".format(number.value))
    except Exception as e:
    raise e

    if __name__ == '__main__':
    print("start main")
    number = Value('d', 0) #这里创建了一个共享内存
    p1 = multiprocessing.Process(target=add1, args=(1, number))
    p3 = multiprocessing.Process(target=add3, args=(3, number))
    p1.start()
    p3.start()
    print("end main")

    输出结果:
    start main
    end main
    start add1 number= 0.0
    number = 1.0
    number = 2.0
    number = 3.0
    number = 4.0
    start add3 number= 4.0
    number = 7.0
    number = 10.0
    number = 13.0
    number = 16.0

    #这里运行的结果也是按照每个进程顺序来的,可以得出的是在共享内存里会默认给每个进程加一个锁,避免进程间乱套

    以上实现的数据共享的方式只有两种结构Value和Array。Python中提供了强大的Manage专门用来做数据共享的,其支持的类型非常多,包括,Value, Array,list,dict, Queue, Lock等。

    下面看个例子:

    from multiprocessing import Process, Manager
    def func(dt, lt):
    for i in range(10):
    key = 'arg' + str(i)
    dt[key] = i * i
    lt += range(11, 16)

    if __name__ == "__main__":
    manager = Manager()
    dt = manager.dict()
    lt = manager.list()
    p = Process(target=func, args=(dt, lt))
    p.start()
    p.join()
    print(dt)
    print(lt)

     1.8、进程池

      Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程。

    示例:

    import time
    import multiprocessing

    def fun(msg):
    print("#########start#### {0}".format(msg))
    time.sleep(3)
    print("#########end###### {0}".format(msg))

    if __name__ == '__main__':
    print("start main")
    pool = multiprocessing.Pool(processes=3)
    for i in range(1, 7):
    msg = "hello {0}".format(i)
    pool.apply_async(fun, (msg,))# 执行时间6s+
    # pool.apply(fun, (msg,)) 6*3=18+#执行时间
    pool.close()#在调用join之前,要先调用close,否则会报错,close执行完不会有新的进程加入到pool
    pool.join()#join 是等待所有的子进程结束
    print("end main")

    1.9、进程池阻塞和非阻塞的区别:

    • Pool.apply_async         非阻塞,定义的进程池进程最大数可以同时执行。
    • Pool.apply                    一个进程结束,释放回进程池,下一个进程才可以开始
     
  • 相关阅读:
    转:什么是即时编译(JIT)!?OpenJDK HotSpot VM剖析
    用好spring mvc validator可以简化代码
    接口服务中的日志
    rest api参数与content-type
    【单页应用】全局控制器app应该干些什么?
    【webapp的优化整理】要做移动前端优化的朋友进来看看吧
    【单页应用】理解MVC
    【单页应用】view与model相关梳理
    【单页应用之通信机制】view之间应该如何通信
    【单页应用巨坑之History】细数History带给单页应用的噩梦
  • 原文地址:https://www.cnblogs.com/Jweiqing/p/9064287.html
Copyright © 2011-2022 走看看