Python的multiprocessing多进程

https://www.cnblogs.com/tkqasn/p/5701230.html

由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程。Python提供了非常好用的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。multiprocessing支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

multiprocessing包是Python中的多进程管理包。与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。该进程可以运行在Python程序内部编写的函数。该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

但在使用这些共享API的时候,我们要注意以下几点:

  • 在UNIX平台上,当某个进程终结之后,该进程需要被其父进程调用wait,否则进程成为僵尸进程(Zombie)。所以,有必要对每个Process对象调用join()方法 (实际上等同于wait)。对于多线程来说,由于只有一个进程,所以不存在此必要性。
  • multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。
  • 多进程应该避免共享资源。在多线程中,我们可以比较容易地共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过共享内存和Manager的方法来共享资源。但这样做提高了程序的复杂度,并因为同步的需要而降低了程序的效率。

Process.PID中保存有PID,如果进程还没有start(),则PID为None。

window系统下,需要注意的是要想启动一个子进程,必须加上那句if __name__ == “__main__”,进程相关的要写在这句下面。

简单创建多进程:

有两种使用方法,直接传入要运行的方法或从Process继承并覆盖run():

from multiprocessing import Process
import threading
import timedef foo(i):print 'say hi', iif __name__ == '__main__':for i in range(10):p = Process(target=foo, args=(i,))p.start()
say hi 4
say hi 3
say hi 5
say hi 2
say hi 1
say hi 6
say hi 0
say hi 7
say hi 8
say hi 9Process finished with exit code 0

可以看出多个进程随机顺序执行

from multiprocessing import Process
import time
class MyProcess(Process):def __init__(self, arg):super(MyProcess, self).__init__()self.arg = argdef run(self):print 'say hi', self.argtime.sleep(1)if __name__ == '__main__':for i in range(10):p = MyProcess(i)p.start()

Process类

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])

  • group: 线程组,目前还没有实现,库引用中提示必须是None;
  • target: 要执行的方法;
  • name: 进程名;
  • args/kwargs: 要传入方法的参数。

实例方法:

  • is_alive():返回进程是否在运行。

  • join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。

  • start():进程准备就绪,等待CPU调度

  • run():strat()调用run方法,如果实例进程时未制定传入target,这star执行t默认run()方法。

  • terminate():不管任务是否完成,立即停止工作进程

属性:

  • authkey

  • daemon:和线程的setDeamon功能一样

  • exitcode(进程在运行时为None、如果为–N,表示被信号N结束)

  • name:进程名字。

  • pid:进程号。

例子一:

from multiprocessing import Process
import threading
import timedef foo(i):print 'say hi',ifor i in range(10):p = Process(target=foo,args=(i,))p.start()
say hi 0
say hi 3
say hi 6
say hi 1
say hi 8
say hi 2
say hi 5
say hi 4
say hi 7
say hi 9Process finished with exit code 0

例子二:

def foo(i):time.sleep(1)print 'say hi', itime.sleep(1)if __name__ == '__main__':p_list=[]for i in range(10):p = Process(target=foo, args=(i,))p.daemon=Truep_list.append(p)for p in p_list:p.start()for p in p_list:p.join()print 'main process end'
say hi 1
say hi 2
say hi 5
say hi 6
say hi 7
say hi 0
say hi 4
say hi 3
say hi 8
say hi 9
main process endProcess finished with exit code 0

可以看出join()方法和deamon属性的用法和多线程的基本一致。

Pool类

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。进程池设置最好等于CPU核心数量

构造方法:

Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])

  • processes :使用的工作进程的数量,如果processes是None那么使用 os.cpu_count()返回的数量。
  • initializer: 如果initializer是None,那么每一个工作进程在开始的时候会调用initializer(*initargs)。
  • maxtasksperchild:工作进程退出之前可以完成的任务数,完成后用一个新的工作进程来替代原进程,来让闲置的资源被释放。- maxtasksperchild默认是None,意味着只要Pool存在工作进程就会一直存活。
  • context: 用在制定工作进程启动时的上下文,一般使用 multiprocessing.Pool() 或者一个context对象的Pool()方法来创建一个池,两种方法都适当的设置了context

实例方法:

  • apply(func[, args[, kwds]]):同步进程池

  • apply_async(func[, args[, kwds[, callback[, error_callback]]]]) :异步进程池

  • close() : 关闭进程池,阻止更多的任务提交到pool,待任务完成后,工作进程会退出。

  • terminate() : 结束工作进程,不在处理未完成的任务

  • join() : wait工作线程的退出,在调用join()前,必须调用close() or terminate()。这样是因为被终止的进程需要被父进程调用wait(join等价与wait),否则进程会成为僵尸进程。pool.join()必须使用在

例子一(异步进程池):

pool.close()或者pool.terminate()之后。其中close()跟terminate()的区别在于close()会等待池中的worker进程执行结束再关闭pool,而terminate()则是直接关闭。

# coding:utf-8
from  multiprocessing import Pool
import timedef Foo(i):time.sleep(2)return i + 100def Bar(arg):print argif __name__ == '__main__':t_start=time.time()pool = Pool(5)for i in range(10):pool.apply_async(func=Foo, args=(i,), callback=Bar)#维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去pool.close()pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。pool.terminate()t_end=time.time()t=t_end-t_startprint 'the program time is :%s' %t
101
100
102
103
104
106
105
107
108
109
the program time is :4.22099995613Process finished with exit code 0

例子二(同步进程池):

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from  multiprocessing import Process, Pool
import timedef Foo(i):time.sleep(1)print i + 100if __name__ == '__main__':t_start=time.time()pool = Pool(5)for i in range(10):pool.apply(Foo, (i,))pool.close()pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。t_end=time.time()t=t_end-t_startprint 'the program time is :%s' %t
100
101
102
103
104
105
106
107
108
109
the program time is :10.2409999371Process finished with exit code 0

可以看出进程同步顺序执行了,效率降低

例子三:异步进程池使用get()方法获得进程执行结果值(错误使用get()方法获取结果)

def Bar(arg):return argif __name__ == '__main__':t_start=time.time()pool = Pool(5)for i in range(10):res = pool.apply_async(func=Foo, args=(i,), callback=Bar)#维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去print res.get()pool.close()pool.join()  # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。pool.terminate()t_end=time.time()t=t_end-t_startprint 'the program time is :%s' %t
100
101
102
103
104
105
106
107
108
109
the program time is :20.2850000858Process finished with exit code 0

可以看出由于每个进程的get()方法,程序变成同步执行了

例子四(正确使用get()方法获取结果)

# coding:utf-8
from  multiprocessing import Pool
import timedef Foo(i):time.sleep(2)return i + 100def Bar(arg):return argif __name__ == '__main__':res_list=[]t_start=time.time()pool = Pool(5)for i in range(10):res = pool.apply_async(func=Foo, args=(i,), callback=Bar)res_list.append(res)pool.close()pool.join()for res in res_list:print res.get()t_end=time.time()t=t_end-t_startprint 'the program time is :%s' %t
100
101
102
103
104
105
106
107
108
109
the program time is :4.22399997711Process finished with exit code 0

进程数据共享

进程各自持有一份数据,默认无法共享数据

#!/usr/bin/env python
# coding:utf-8from multiprocessing import Process
li = []def foo(i):li.append(i)print 'say hi', li
if __name__ == '__main__':for i in range(10):p = Process(target=foo, args=(i,))p.start()print 'ending', li

期望输出[0到10的随机排列的列表]

say hi [1]
say hi [0]
say hi [2]
say hi [3]
say hi [4]
say hi [5]
ending []
say hi [6]
say hi [7]
say hi [8]
say hi [9]Process finished with exit code 0

方法一(使用Array):

Array(‘i’, range(10))中的‘i’参数C语言中的类型:

‘c’: ctypes.c_char     ‘u’: ctypes.c_wchar    ‘b’: ctypes.c_byte     ‘B’: ctypes.c_ubyte
‘h’: ctypes.c_short     ‘H’: ctypes.c_ushort    ‘i’: ctypes.c_int      ‘I’: ctypes.c_uint
‘l’: ctypes.c_long,    ‘L’: ctypes.c_ulong    ‘f’: ctypes.c_float    ‘d’: ctypes.c_double
from multiprocessing import Process, Arraydef f(a):for i in range(len(a)):a[i] = -a[i]if __name__ == '__main__':arr = Array('i', range(10))p = Process(target=f, args=(arr,))p.start()p.join()print(arr[:])
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

方法二(使用Manager):

Manager()返回的manager提供list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array类型的支持。

from multiprocessing import Process, Managerdef f(d, l):d[1] = '1'd['2'] = 2d[0.25] = Nonel.reverse()if __name__ == '__main__':with Manager() as manager:d = manager.dict()l = manager.list(range(10))p = Process(target=f, args=(d, l))p.start()p.join()print(d)print(l)
{0.25: None, 1: '1', '2': 2}
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]Process finished with exit code 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402125.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 字符设备驱动结构(三)—— file、inode结构体及chardevs数组等相关知识解析

前面我们学习了字符设备结构体cdev Linux 字符设备驱动开发 (一)—— 字符设备驱动结构(上) 下面继续学习字符设备另外几个重要的数据结构。 先看下面这张图,这是Linux 中虚拟文件系统、一般的设备文件与设备驱动程序…

Python的gevent协程及协程概念

https://www.cnblogs.com/tkqasn/p/5705338.html 何为协程 协程,又称微线程。英文名Coroutine。 协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,…

技术人生:三亚之行

人生收获 此次是公司组团去的三亚,地接的导游非常热情,如同大多数人一样,导游也会在这短短的几天内,尽可能的表现自己,此文聊聊导游说的三句话。 旅游三不“较”: 不比较不计较不睡觉人生何尝不是如此&…

Linux 字符设备驱动结构(二)—— 自动创建设备节点

上一篇我们介绍到创建设备文件的方法,利用cat /proc/devices查看申请到的设备名,设备号。 第一种是使用mknod手工创建:mknod filename type major minor 第二种是自动创建设备节点:利用udev(mdev)来实现设备…

Python数据库使用-SQLite

https://www.liaoxuefeng.com/wiki/897692888725344/926177394024864 SQLite是一种嵌入式数据库,它的数据库就是一个文件。由于SQLite本身是C写的,而且体积很小,所以,经常被集成到各种应用程序中,甚至在iOS和Android的…

Linux 字符设备驱动结构(一)—— cdev 结构体、设备号相关知识解析

一、字符设备基础知识 1、设备驱动分类 linux系统将设备分为3类:字符设备、块设备、网络设备。使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数…

Python数据库使用MySQL

https://www.liaoxuefeng.com/wiki/897692888725344/932709047411488 MySQL是Web世界中使用最广泛的数据库服务器。SQLite的特点是轻量级、可嵌入,但不能承受高并发访问,适合桌面和移动应用。而MySQL是为服务器端设计的数据库,能承受高并发访…

Linux 驱动开发之内核模块开发(四)—— 符号表的导出

Linux内核头文件提供了一个方便的方法用来管理符号的对模块外部的可见性,因此减少了命名空间的污染(命名空间的名称可能会与内核其他地方定义的名称冲突),并且适当信息隐藏。 如果你的模块需要输出符号给其他模块使用,应当使用下面的宏定义: EXPORT_SYMBOL(name); EXPORT_SYMBO…

Python的time模块和datatime模块

https://www.cnblogs.com/tkqasn/p/6001134.html

Linux 驱动开发之内核模块开发 (三)—— 模块传参

一、module_param() 定义 通常在用户态下编程,即应用程序,可以通过main()的来传递命令行参数,而编写一个内核模块,则通过module_param() 来传参。 module_param()宏是Linux 2.6内核中新增的,该宏被定义在include/linux…

Linux 驱动开发之内核模块开发 (二)—— 内核模块编译 Makefile 入门

一、模块的编译 我们在前面内核编译中驱动移植那块,讲到驱动编译分为静态编译和动态编译;静态编译即为将驱动直接编译进内核,动态编译即为将驱动编译成模块。 而动态编译又分为两种: a -- 内部编译 在内核源码目录内编译 b -- 外部…

Exynos4412 文件系统制作(三)—— 文件系统移植

根文件系统一直以来都是所有类Unix操作系统的一个重要组成部分,也可以认为是嵌入式Linux系统区别于其他一些传统嵌入式操作系统的重要特征,它给Linux带来了许多强大和灵活的功能,同时也带来了一些复杂性。我们需要清楚的了解根文件系统的基本…

Snapchat, 给年轻人要的安全感

这几天,Snapchat因拒绝Facebook和谷歌的收购请求而名声大噪。40亿美金的收购请求,并不是任何一个人都可以淡然处之的。一、关于SnapchatSnapchat由两位斯坦福大学生创办,在2011 年9月上线。Snapchat的主要是所有照片都有一个1到10秒的生命期&…

Exynos4412 文件系统制作(二)—— 文件系统简介

一、Linux磁盘分区和目录 Linux发行版本之间的差别很少,差别主要表现在系统管理的特色工具以及软件包管理方式的不同。目录结构基本上都是一样的。 Windows的文件结构是多个并列的树状结构,最顶部的是不同的磁盘(分区)&#xff0c…

python的urllib2模块

https://www.cnblogs.com/erliang/p/4063883.html https://blog.csdn.net/u014343243/article/details/49308043 https://docs.python.org/zh-cn/2.7/library/urllib2.html

Python中的yield

《python中yield的用法详解——最简单,最清晰的解释》 https://www.ibm.com/developerworks/cn/opensource/os-cn-python-yield/ https://www.runoob.com/w3cnote/python-yield-used-analysis.html

Exynos4412 内核移植(七)—— 内核相关知识补充

一、内核调试方法简单分析 1、addr2line: 解决oops错误 a -- oops消息 oops(也称 panic),称程序运行崩溃,程序崩溃后会产生oops消息。应用程序或内核线程的崩溃都会产生oops消息,通常发生oops时,系统不会发…

MM引擎新应用——爱车加油记

基于MM应用引擎开发的EXTJS应用,车主每次加完汽油后,记录加油时的里程数以及加油金额和汽油价格,就可计算出上次加油后行驶的里程数、上次加油的平均油耗。点击刷新按钮,即可计算有记录以来的行驶公里数和再次期间加油金额和平均油…

Python风格

Python3学习之Python风格指南 PEP8 – Python代码样式指南(中文版)