python多进程利用Multiprocessing运行程序

参考链接:
multiprocessing官网
https://blog.csdn.net/cityzenoldwang/article/details/78584175 博主整理
https://blog.csdn.net/quqiuzhu/article/details/51156454博主整理

Process类

Process 类用来描述一个进程对象。创建子进程的时候,只需要传入一个执行函数和函数的参数即可完成 Process 示例的创建。

  • star() 方法启动进程,
  • join() 方法实现进程间的同步,等待所有进程退出才执行下面的代码
  • close() 用来阻止多余的进程涌入进程池 Pool 造成进程阻塞。
    multiprocessing.Process(group=None, target=None, name=None,args=(), kwargs={},daemon=None)
  • target 是函数名字,需要调用的函数
  • args 函数需要的参数,以 tuple 的形式传入,当传入一个参数是,要加,号,因为(1)不是一个tuple,而(1,)才是一个tuple

给函数分配进程运行实例,创建单进程:

import multiprocessing as mp


def job(a, b):
    print(a+b)


if __name__ == '__main__':  # 必须将进程过程放到main函数中去
    p1 = mp.Process(target=job, args=(1, 2))  
    p1.start()
    p1.join()

创建多进程:

import multiprocessing
import os


def run_proc(name):
    print('Child process {0} {1} Running '.format(name, os.getpid()))


if __name__ == '__main__':
    print('Parent process {0} is Running'.format(os.getpid()))
    for i in range(5):
        p = multiprocessing.Process(target=run_proc, args=(str(i),))
        print('process start')
        p.start()
    p.join()
    print('Process close')

运行结果:

Parent process 6296 is Running
process start
process start
process start
process start
process start
Child process 0 9428 Running 
Child process 1 8444 Running 
Child process 2 7852 Running 
Child process 3 6540 Running 
Child process 4 14472 Running 
Process close

如果将p.join去掉,结果为:

Parent process 8712 is Running
process start
process start
process start
process start
process start
Child process 0 10516 Running 
Process close
Child process 1 3172 Running 
Child process 2 10748 Running 
Child process 3 11636 Running 
Child process 4 5484 Running 

Queue

使用Queue存储进程输出,用于多个进程间的通信
Queue的功能是将每个核或线程的运算结果放在队里中, 等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。原因很简单, 多进程调用的函数不能有返回值(不能return), 所以使用Queue存储多个进程运算的结果。
put方法:插入数据到队列。
get方法:从队列中读取并删除一个元素。

import multiprocessing as mp


def job(q):
    for i in range(10):
        q.put(i)  # 存放到队列中


if __name__ == '__main__':
    q = mp.Queue()  # 创建队列
    # args里一个参数时要加,号,否则会报错参数是不可迭代的
    p1 = mp.Process(target=job, args=(q,))
    p2 = mp.Process(target=job, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()  # 获取队列中的值
    res2 = q.get()
    res3 = q.get()
    print(res1)  # 0
    print(res2)  # 1
    print(res3)  # 2

Pool进程池

进程池就是我们将所要运行的东西,放到进程池中,Python会自行解决多进程的问题。Pool默认大小是CPU的核数,我们也可以通过在Pool中传入processes参数自定义需要的核数量。定义进程池之后,就可以让进程池对应某一个函数,通过向进程池中传入数据从而返回函数值。 Pool和之前的Process的不同点是传入Pool的函数有返回值,而Process的没有返回值。
map方法:用map()获取结果,在map()中需要放入函数和需要迭代运算的值,然后它会自动分配给CPU核,返回结果。
apply_async方法:apply_async()中只能传递一个值,它只会放入一个核进行运算,但是传入值时要注意是元组类型,所以在传入值后需要加逗号, 同时需要用get()方法获取返回值。如果要实现map()的效果,需要将apply_async方法做成一个列表的形式。
进程池最后要加join方法,这样进程池运行完毕后才向下进行,如果不加的话可能导致进程池还未运行完程序已经finished。
代码如下。

import multiprocessing as mp


def job(x):
    return x * x


def multicore():
    pool = mp.Pool(processes=mp.cpu_count() - 1)
    res = pool.map(job, range(10))
    print(res)
    res = pool.apply_async(job, (2,))
    print(res.get())
    multi_res = [pool.apply_async(job, (i,)) for i in range(10)]
    pool.close()  # 关闭进程池,其他进程无法加入
    pool.join()  # 等待所有进程执行完毕,调用前必须调用close方法
    print([res.get() for res in multi_res])


if __name__ == '__main__':
        multicore()

运行结果:

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
4
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

多进程(multiprocessing)和多线程(multi-threading)对比:

测试程序:

import multiprocessing as mp
import threading as td
import time


MAX = 10000000


def job(q):
    res = 0
    for i in range(MAX):
        res += i+i**2+i**3
    q.put(res)


def multicore():
    q = mp.Queue()
    p1 = mp.Process(target=job, args=(q,))
    p2 = mp.Process(target=job, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    res1 = q.get()
    res2 = q.get()
    print('multicore:', res1+res2)


def normal():
    res = 0
    for _ in range(2):
        for i in range(MAX):
            res += i+i**2+i**3
    print('normal:', res)

def multithread():
    q = mp.Queue()
    t1 = td.Thread(target=job, args=(q,))
    t2 = td.Thread(target=job, args=(q,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    res1 = q.get()
    res2 = q.get()
    print('multithreading:', res1+res2)


if __name__ == '__main__':
    st = time.time()
    normal()
    st1 = time.time()
    print('normal time:', st1 - st)
    multithread()
    st2 = time.time()
    print('multithreading time:', st2 - st1)
    multicore()
    print('multicore time:', time.time()-st2)

运行结果:

扫描二维码关注公众号,回复: 121694 查看本文章
normal time: 23.027679920196533
multithreading: 4999999666666716666660000000
multithreading time: 24.3942768573761
multicore: 4999999666666716666660000000
multicore time: 19.363178968429565

从上述结果来看,多进程的时间是要小于多线程和正常程序的,多线程的时间与正常时间相差无几。原因是Python解释器有一个全局解释器锁(GIL),导致每个Python进程最多同时运行一个线程,因此Python多线程程序并不能改善程序性能,不能发挥CPU多核的优势,通过GIL这篇文章可以了解。但是多进程程序可以不受影响,Python2.6引入multiprocessing来解决多进程问题,而multiprocessing的API几乎是复制了threading的API。

猜你喜欢

转载自blog.csdn.net/winycg/article/details/79701166