python 实现多进程


参考链接: https://morvanzhou.github.io/tutorials/python-basic/multiprocessing/

python中实现多进程的模块:multiprocessing

注意:在windows系统下,要想启动一个子进程,必须把进程相关的内容写在”if __name__ == “__main__” ”,这句话下面。

具体实现模块

1、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:进程号。

  • 例子:

 import multiprocessing

 def job(a,d):
  print('aaaaa') if __name__ == “__main__”:
  p1 = multiprocessing.Process(target=job,args=(1,2))
  p1.start()
  p1.join()

2、Pool模块

  • 实现功能:

创建管理进程池。提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行它。在共享资源时,只能使用Multiprocessing.Manager类,而不能使用Queue或者Array。

  • 构造方法:

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

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

  • 实例方法:

apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞。
apply(func[, args[, kwds]])是阻塞的。
close() 关闭pool,使其不在接受新的任务。
terminate() 关闭pool,结束工作进程,不在处理未完成的任务。
join() 主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用。

  • Pool使用方法:

1、Pool+map函数

  • 用map()获取结果,在map()中需要放入函数和需要迭代运算的值,然后它会自动分配给CPU核,返回结果。
  • 说明:此写法缺点在于只能通过map向函数传递一个参数。
 from multiprocessing import Pool

 def test(i):
print i if __name__=="__main__":
lists=[1,2,3]
pool=Pool(processes=2) #定义最大的进程数
pool.map(test,lists) #lists必须是一个可迭代变量。
pool.close()
pool.join()

2、异步进程池(非阻塞)

  • apply_async()只能放入一组参数,并返回一个结果,如果想得到map()的效果需要通过迭代。
 from multiprocessing import Pool

 def test(i):
print i if __name__=="__main__":
pool = Pool(processes=10)
for i in xrange(500):
'''
For循环中执行步骤:
(1)循环遍历,将500个子进程添加到进程池(相对父进程会阻塞)
(2)每次执行10个子进程,等一个子进程执行完后,立马启动新的子进程。(相对父进程不阻塞)
apply_async为异步进程池写法。
异步指的是启动子进程的过程,与父进程本身的执行(print)是异步的,而For循环中往进程池添加子进程的过程,与父进程本身的执行却是同步的。
'''
pool.apply_async(test, args=(i,)) #维持执行的进程总数为10,当一个进程执行完后启动一个新进程.
print“test”
pool.close()
pool.join()

代码说明:

执行顺序:For循环内执行了2个步骤,第一步:将500个对象放入进程池(阻塞)。第二步:同时执行10个子进程(非阻塞),有结束的就立即添加,维持10个子进程运行。(apply_async方法的会在执行完for循环的添加步骤后,直接执行后面的print语句,而apply方法会等所有进程池中的子进程运行完以后再执行后面的print语句)

注意:调用join之前,先调用close或者terminate方法,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束。

3、同步进程池(阻塞)

 from multiprocessing import Pool

 def test(p):
print p
time.sleep(3) if __name__=="__main__":
pool = Pool(processes=10)
for i in xrange(500):
'''
实际测试发现,for循环内部执行步骤:
(1)遍历500个可迭代对象,往进程池放一个子进程
(2)执行这个子进程,等子进程执行完毕,再往进程池放一个子进程,再执行。(同时只执行一个子进程)
for循环执行完毕,再执行print函数。
'''
pool.apply(test, args=(i,)) #维持执行的进程总数为10,当一个进程执行完后启动一个新进程.
print“test”
pool.close()
pool.join()

代码说明:

for循环内执行的步骤顺序,往进程池中添加一个子进程,执行子进程,等待执行完毕再添加一个子进程…..等500个子进程都执行完了,再执行print “test”。(从结果来看,并没有多进程并发

3、Queue模块

  • 实现功能:

将每个核或线程的运算结果放在队列中,等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。原因很简单, 多线程调用的函数不能有返回值, 所以使用Queue存储多个线程运算的结果

  • 例子:

 import multiprocessing as mp

 def job(q):
res=0
for i in range(1000):
res+=i+i**2+i**3
q.put(res) #queue if __name__=='__main__':
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(res1+res2)

4、Pipe模块

  • 实现功能:

用来管道操作。

5、Manager模块

  • 实现功能:

Manager模块常与Pool模块一起使用,作用是共享资源。

6、Lock模块(进程锁)

  • 实现功能:

当多个进程需要访问共享资源的时候,Lock可以用来避免访问的冲突。

  • 实现步骤:

1)首先需要定义一个进程锁

l = multiprocessing.Lock()    # 定义一个进程锁

2)然后将进程锁的信息传入各个进程中

p1 = multiprocessing.Process(target=job, args=(v,1,l))    # 需要将Lock传入
p2 = multiprocessing.Process(target=job, args=(v,3,l))

3)在job()中设置进程锁的使用,保证运行时一个进程的对锁内内容的独占

  • 例子:

 import multiprocessing as mp

 def job(v, num, l):
l.acquire() # 锁住
for _ in range(5):
time.sleep(0.1)
v.value += num # 获取共享内存
print(v.value)
l.release() # 释放 def multicore():
l = mp.Lock() # 定义一个进程锁
v = mp.Value('i', 0) # 定义共享内存
p1 = mp.Process(target=job, args=(v,1,l)) # 需要将lock传入
p2 = mp.Process(target=job, args=(v,3,l))
p1.start()
p2.start()
p1.join()
p2.join() if __name__ == '__main__':
multicore()

共享内存

Multiprocessing类中共享资源可以使用3种方式,分别是Queue,Array,Manager。

1、Queue类

使用Multiprocessing.Queue类,共享资源(share memory)(只适用Process类,不能再Pool进程池中使用)

 from multiprocessing import Process, Queue

 def test(queue):
queue.put("Hello World") if __name__ == '__main__':
q = Queue()
p = Process(target=test, args=(q,)) #需要将q对象传递给子进程
p.start()
Print q.get()

2、Array、Value类

使用Multiprocessing.Array类,共享资源(share memory)(只适用于Process类,无法与Pool一起使用)

 from multiprocessing import Process, Array

 def test(a):
for i in range(len(a)):
a[i] = -a[i] if__name__ == '__main__':
arr = Array('i', range(10))
p = Process(target=test, args=(arr)) #需要将arr对象传递给子进程
p.start()
p.join()
print arr[:]
  • 单值:Value

  我们可以通过使用Value数据存储在一个共享的内存表中。

 import multiprocessing as mp 
value1 = mp.Value('i', 0)
value2 = mp.Value('d', 3.14)
  
# 其中d和i参数用来设置数据类型的,d表示一个双精浮点类型,i表示一个带符号的整型。
  • 列表:Array

  在Python的mutiprocessing中,有还有一个Array类,可以和共享内存交互,来实现在进程之间共享数据。

 array = mp.Array('i', [1, 2, 3, 4])
  
#这里的Array和numpy中的不同,它只能是一维的,不能是多维的。同样和Value 一样,需要定义数据形式,否则会报错。

3、Manager类

使用Multiprocessing.Manager类,共享资源。(可以适用Pool类)
实例目的:父进程在执行子进程的过程中,同步判断一个公共资源值,如果满足条件则结束所有进程。

 from multiprocessing import Manager

 def test(i,lists):
print i
lists.append(i) if __name__=="__main__":
pool=Pool()
lists=Manager().list() #Manager类实例化代码只能写在main()函数里面
for i in xrange(10000000):
if len(lists)<=0:
'''
在创建子进程时,需要将lists对象传入,不然无法共享。
'''
pool.apply_async(test,args=(i,lists))##需要将lists对象传递给子进程,这里比较耗资源,原因可能是因为Manager类是基于通信的。
else:
break

  

  • 父进程中的全局变量能被子进程共享吗?

解答:不行,因为每个进程享有独立的内存数据,如果想要共享资源,可以使用Manage类,或者Queue等模块。

进程与线程(2)- python实现多进程的更多相关文章

  1. Python进阶(4)_进程与线程 (python并发编程之多进程)

    一.python并发编程之多进程 1.1 multiprocessing模块介绍 由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大 ...

  2. 进程 vs. 线程(python的协程)(转廖雪峰老师python教程)

    我们介绍了多进程和多线程,这是实现多任务最常用的两种方式.现在,我们来讨论一下这两种方式的优缺点. 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Work ...

  3. Python基础进程和线程

    一 背景知识 进程的概念起源于操作系统,是操作系统最核心的概念. 进程是对正在运行程序的一个抽象,操作系统的其他所有内容都是围绕进程的概念展开的.所以想要真正了解进程,必须事先了解操作系统,egon介 ...

  4. 【Python】进程和线程

    多进程 多线程 ThreadLocal 进程vs线程 分布式进程 Top 学习廖老师的py官网的笔记 多任务的实现方式有三种方式: 1.多进程 2.多线程 3.多进程+多线程(这种比较复杂,实际很少采 ...

  5. Python语法进阶(1)- 进程与线程编程

    1.进程与多进程 1.1.什么是进程 进程就是程序执行的载体 什么叫多任务? 多任务就是操作系统可以同时运行多个任务.比如你一边在用浏览器学习,还一边在听音乐,,这就是多任务,至少同时有3个任务正在运 ...

  6. 进程和线程(4)-进程 vs. 线程

    进程 vs. 线程 我们介绍了多进程和多线程,这是实现多任务最常用的两种方式.现在,我们来讨论一下这两种方式的优缺点. 首先,要实现多任务,通常我们会设计Master-Worker模式,Master负 ...

  7. Linux的进程、线程、文件描述符是什么

    说到进程,恐怕面试中最常见的问题就是线程和进程的关系了,那么先说一下答案:在 Linux 系统中,进程和线程几乎没有区别. Linux 中的进程就是一个数据结构,看明白就可以理解文件描述符.重定向.管 ...

  8. Python 3 并发编程多进程之进程与线程

    Python 3 进程与线程 进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的 ...

  9. 进程,线程,以及Python的多进程实例

    什么是进程,什么是线程? 进程与线程是包含关系,进程包含了线程. 进程是系统资源分配的最小单元,线程是系统任务执行的最小单元. 打个比方,打开word,word这个程序是一个进程,里面的拼写检查,字数 ...

随机推荐

  1. hiberinate二级缓存

    hibernate.cfg.xml配置 <!-- 二级缓存类型 --> <property name="hibernate.cache.region.factory_cla ...

  2. 程序设计之另一种读写函数---writev,readv

    read()和write()系统调用每次在文件和进程的地址空间之间传送一块连续的数据.但是,应用有时也需要将分散在内存多处地方的数据连续写到文件中,或者反之.在这种情况下,如果要从文件中读一片连续的数 ...

  3. Asp.net常用的51个代码(非常实用)

    1.//弹出对话框.点击转向指定页面 Response.Write("<script>window.alert('该会员没有提交申请,请重新提交!')</script> ...

  4. Vue 之 npm 及 安装的包

    1  npm相关 1.1 npm 是 基于Node.js 的,所以要先安装Node.js 在浏览器地址栏输入https://nodejs.org/en/, 进入Node.js官网后,点击下载左边的稳定 ...

  5. SSM整理笔记3——配置解析

    github:https://github.com/lakeslove/SSM 项目的目录结构如下 首先,配置web.xml <?xml version="1.0" enco ...

  6. InspectIT_EUM 实现原理概述

    在Git上查看 InspectIT 实现原理概述: 实现原理详解:  1.jsAgent如何注入到浏览器 通过ASM框架修改HttpService.service()方法,加入相关逻辑,对每一个Htt ...

  7. Hadoop spark mongo复制集

    启动hadoop cd /usr/local/hadoop/hadoop $hadoop namenode -format # 启动前格式化namenode $./sbin/start-all.sh ...

  8. I2C测试【转】

    本文转载自: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 ...

  9. chmod更改文件的权限

    #include "apue.h" int main(int argc,char *argv[]) { struct stat stabuf; ) err_sys("st ...

  10. Microsoft.XMLHTTP基本用法

    客户端调用XMLHTTP的过程很简单,只有5个步骤:1.创建XMLHTTP对象2.打开与服务端的连接,同时定义指令发送方式,服务网页(URL)和请求权限等.客户端通过Open命令打开与服务端的服务网页 ...