Python - 多进程使用教程

什么是Multiprocessing?

    大部分计算机cpu都是多核的,为了提高效率,把程序分配到多个核里面同时运行,这就叫多进程。

    Python提供了一个mulitprocessing 库来实现多进程

    (本文是学习“莫烦Python后写的总结,分析与感悟。这里是莫烦python的连接: >点这里< )

1:基本操作:创建进程

    a. 创建一个函数,且不能有返回值

    b. 创建子进程对象,函数名传递给 target,参数放在一个可迭代对象内传递给 args,(注意,若只有一个元素1,且是放在小括号内,则应该写为:args = (1,) 因为加个逗号才算是元组,才可迭代)

    c. 运行子进程(注意!!需要在if __name__ == '__main__':下运行

'''创建进程'''

import multiprocessing as mp

def job_1(a, b):
    for _ in range(5):
        print("job_1 is running")


if __name__ == '__main__':
    print("main start")
    #创建子进程
    p1 = mp.Process(target=job_1, args=(1, 2))
    #子进程开始运行
    p1.start()
    print("main end")

    这个时候,main相当于主进程,p1是他的子进程,一旦运行到p1.start(),job1才开始运行。而main 和 p1各自运行各自的,并不会相互等待,所以就出现了以下结果:

    Python - 多进程使用教程_第1张图片

 

2.等待主进程:join()

     join()的官方解释:阻塞当前进程,直到调用join方法的那个进程执行完。

    意思就是:等当前子进程(p1 或 p2) 运行完毕之后,主进程(main)才继续运行。(注意:如果两个子进程都使用join,子进程之间不会互相等待,仍然是各走各的)

    # 只需要把join放在主进程需要等待的地方即可

    准备工作:

import multiprocessing as mp
import time

def run_1():
    for _ in range(5):
        time.sleep(0.1)
        print("job_1 is runing...")

def run_2():
    for _ in range(5):
        time.sleep(0.1)
        print("job_2 is runing...")

if __name__ == '__main__':
    print("main start")
    p1 = mp.Process(target=run_1)
    p2 = mp.Process(target=run_2)

    情况1:main, p1, p2 三个进程互不干扰

    p1.start()
    p2.start()
    print("main end")

       结果:各自运行,非常混乱

                 Python - 多进程使用教程_第2张图片

       情况2:p1, p2都调用join()

    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("main end")

     结果:主程序等待p1, p2运行完了之后才运行,但是p1, p2依旧混乱

               Python - 多进程使用教程_第3张图片

    情况3:p1调用join()之后再调用p2

    p1.start()
    p1.join()
    p2.start()
    print("main end")

    结果有些许奇怪,这是为什么呢?因为p1 调用join之后,main程序在等待p1运行完的时候,根本还没开始运行代码 p2.start() !

"               Python - 多进程使用教程_第4张图片

 

3.特殊的返回值的方法:Queue

    多进程中,可以利用队列来存储返回值,在进程结束之后再调取存储的返回值

    a.声明一个queue,并把queue作为参数传入方法中

    b.待进程结束后提取 “返回值” 

import multiprocessing as mp
import time

def job_1(q, a, b):
    sum = a * b
    q.put(sum)

def job_2(q, a, b):
    sum = a / b
    q.put(sum)

if __name__ == '__main__':
    q = mp.Queue()
    p1 = mp.Process(target=job_1, args=(q, 1, 2))
    p2 = mp.Process(target=job_2, args=(q, 1, 2))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(q.get(), q.get())

 

4.一个池子:pool

    pool也叫做进程池,就是我们将所要运行的东西,放到池子里,Python会自行解决多进程的问题

    用法0:自定义核的数量:pool = mp.Pool(processes = 2) 即pool对象运行时只使用两个核

    用法1:给pool对象一个函数,并传入一个迭代对象(迭代的是传入的参数),pool会返回一个返回值列表

import multiprocessing as mp

def job(a):
    return a*a

if __name__ == '__main__':
    pool = mp.Pool(processes = 2)
    returns = pool.map(job, range(10))
    print(returns)

    

    用法2:apply_async()方法,这个方法类似于直接调用start(),但它接受了一个返回值,而且一个方法只使用一个核。

if __name__ == '__main__':
    pool = mp.Pool()
    returns = pool.apply_async(job, (3,))
    print(returns.get())

 

5.共同处理数据:共享内存

    如果不用共享变量,传入子程序的参数只是一个副本,并不能改变传入的变量的值,也不能相互交流

    所以在多核处理的特殊情况下,我们需要用到共享内存处理、需要子进程之间相互交流数据的情况

    操作1:定义单个共享变量:v = mp.Value('i', 0)

    这里我们呢在两个子程序里面分别对变量加 5 次 2,和 5 次 4 预想的最终结果是 30

import multiprocessing as mp

def run_1(a):
    for _ in range(5):
        a.value = a.value + 2
        print(a.value)

def run_2(a):
    for _ in range(5):
        a.value = a.value + 4
        print(a.value)

if __name__ == '__main__':
    v = mp.Value('i', 0)
    p1 = mp.Process(target=run_1, args=(v,))
    p2 = mp.Process(target=run_2, args=(v,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(v.value)

    输出:发现数据实现了共享,且最后也确实被改变成了30。

          2
          8
          10
          12
          14
          6
          18
          22
          26
          30

          30

    操作2:定义变量数组:(注意!!这里只能定义一维数组

array = mp.Array('i', [1, 2, 3, 4])

    

6.维持秩序:lock

    这里回去第 5 节的输出结果,会发现共享的变量被两个进程抢着用,一会儿加2, 一会儿加4, 一会儿你print,一会儿我print

    有时候我们需要两个程序有顺序的完成各自的任务,不能让他们抢夺变量,这是后就可以用到 进程锁

import multiprocessing as mp


def run_1(a, L):
    #锁住
    L.acquire()
    for _ in range(5):
        a.value = a.value + 2
        print(a.value)
    L.release()
    #释放

def run_2(a, L):
    L.acquire()
    for _ in range(5):
        a.value = a.value + 4
        print(a.value)
    L.release()

if __name__ == '__main__':
    v = mp.Value('i', 0)
    #创建进程索
    L = mp.Lock()
    p1 = mp.Process(target=run_1, args=(v,L))
    p2 = mp.Process(target=run_2, args=(v,L))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print(v.value)

     这样一来,输出就变得有序起来了:
          2
          4
          6
          8
          10
          14
          18
          22
          26
          30
          30

你可能感兴趣的:(python)