个人Python成长之路---第八天---Python基础(25)---2016年3月5日(晴)

多进程 multiprocessing模块

multiprocessing模块提供了一个Process类来表明一个进程对象python

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
#!/usr/bin/env python3
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 张晓宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 多进程演示程序
 
Help:
'''
from multiprocessing import Process
import os
 
 
def run_proc(name):
     # 子进程要执行的函数
     print ( 'Run child process %s (%s)...' % (name, os.getpid())) # os.getpid()表示得到当前进程的pid
 
if __name__ = = '__main__' :
     print ( 'Parent process %s.' % os.getpid()) # 打印父进程的pid
     p = Process(target = run_proc, args = ( 'test' ,)) # 建立进程对象,参数结构和多线程同样
     print ( 'Child process will start.' )
     p.start() # 启动子进程
     p.join() # 阻塞等待子进程执行完毕
     print ( 'Child process end.' )

进程间通讯

Queue

不一样进程间内存是不共享,因此多进程不能像多线程同样经过全局变量(固然全局变量也是不提倡的),因此只能经过队列,多进程模块也自带一个队列Queue,使用方法和threading里的queue差很少windows

Pipe

管道,能够理解为两个进程之间的一个桥梁多线程

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
#!/usr/bin/env python3
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 张晓宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 管道演示程序
 
Help:
'''
from multiprocessing import Process, Pipe
 
def f(conn):
     conn.send([ 42 , None , 'hello' ]) # 网管道里传递数据
     conn.close()
 
if __name__ = = '__main__' :
     parent_conn, child_conn = Pipe() # 一个是父进程的管道对象,一个是子进程的对象,本身成往里面send,父进程对象recv,有点像socket
     p = Process(target = f, args = (child_conn,)) # 把管道对象做为参数传递给子进程
     p.start()
     print (parent_conn.recv())   # 接收管道里的数据并打印出来
     p.join()

执行结果app

1
[ 42 , None , 'hello' ]

有人会说既然能够往子进程要执行的而函数传递参数,直接经过这个参数取子进程传递过来的数据就行了,好比能够用列表等可变数据类型(字符串和数值型等不可变类型的数据,想都不要想,统一进程都作不到)为啥还用管道或队列异步

 

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
#!/usr/bin/env python3
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 张晓宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 管道演示程序
 
Help:
'''
from multiprocessing import Process, Pipe
 
def f(conn, strinfo):
     conn.send([ 42 , None , 'hello' ]) # 网管道里传递数据
     conn.close() # 关闭管道
     strinfo.append( 'child' )
 
if __name__ = = '__main__' :
     parent_conn, child_conn = Pipe() # 一个是父进程的管道对象,一个是子进程的对象,本身成往里面send,父进程对象recv,有点像socket
     strinfo = [ 'parent' ]
     p = Process(target = f, args = (child_conn, strinfo)) # 把管道对象做为参数传递给子进程
     p.start()
     print (parent_conn.recv())   # 接收管道里的数据并打印出来
     print (strinfo)
     p.join()

执行结果socket

1
2
[ 42 , None , 'hello' ]
['parent']

从执行结果中能够看出来,strinfo的值并无变化,那是由于,进程启动的时候从新划分了内存空间,等于将strinfo在子进程中copy了一份,已经和父进程中的strinfo没有半毛钱关系了因此要有管道队列等async

进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程, 若是进程池序列没有可提供的进程,那么就会等待,知道有可用进程为止函数

Pool模块有两种经常使用的启动进程的方法spa

apply和apply_assync,从字面上理解是apply_assync是异步的,其实就是apply_assync支持把一个函数做为参数传递进去,当进程函数执行完的时候能够经过return一个值,这个值,会自动做为参数传递个传递进来的函数,并执行该函数,咱们称之为回调(callback)线程

 

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
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python
# coding:utf-8
'''
Created on: 2016年3月5日
 
@author: 张晓宇
 
Email: 61411916@qq.com
 
Version: 1.0
 
Description: 进程池演示程序
 
Help:
'''
from  multiprocessing import Pool, freeze_support
import time
 
def Foo(i):
     '''
     子进程执行的函数
     :param i:
     :return:
     '''
     time.sleep( 2 )
     return i + 100
 
def Bar(arg):
     '''
     子进程回调函数
     :param arg:
     :return:
     '''
     print ( '-->exec done:' ,arg)
 
if __name__ = = '__main__' : # 这个在windows环境中绝对不能省略不然会报错
     freeze_support()
     pool = Pool( 5 ) # 建立进程池对象
 
     for i in range ( 10 ):
         pool.apply_async(func = Foo, args = (i,), callback = Bar)
         # pool.apply(func=Foo, args=(i,))
     print ( 'end' )
     pool.close()
     pool.join() #进程池中进程执行完毕后再关闭,若是注释,那么程序直接关闭。

执行结果

1
2
3
4
5
6
7
8
9
10
11
end
- - > exec done: 100
- - > exec done: 101
- - > exec done: 102
- - > exec done: 103
- - > exec done: 104
- - > exec done: 105
- - > exec done: 106
- - > exec done: 107
- - > exec done: 108
- - > exec done: 109
相关文章
相关标签/搜索