multiprocessing
模块
为再子进程中运行任务、通信和共享数据,以及执行各种形式的同步提供支持。这个编程接口有意模仿
threading
模块中线程的编程接口。但和线程不同,进程没有任何共享状态,这一点需要重点强调。因此如果某个进程修改数据,改动只限于该进程内。
Process([group[,target[,name[,args[,kwargs]]]]])
类
练习
1-1
#! /bin/python
import os
import multiprocessing
import time
def task(intval):
while True:
print('time is %s' % (time.ctime()))
time.sleep(intval)
if __name__ =='__main__':
proc=multiprocessing.Process(target=task,args=(3,))
print('a single process(%s) begin...' % (os.getpid()))
proc.start()
执行结果
time is Tue Feb 6 08:30:54 2018
time is Tue Feb 6 08:30:57 2018
time is Tue Feb 6 08:31:00 2018
time is Tue Feb 6 08:31:03 2018
time is Tue Feb 6 08:31:06 2018
time is Tue Feb 6 08:31:09 2018
time is Tue Feb 6 08:31:12 2018
time is Tue Feb 6 08:31:15 2018
time is Tue Feb 6 08:31:18 2018
time is Tue Feb 6 08:31:21 2018
也可继承
Process
类来实现:
练习
1-2
#python简单的进程操作
#一个进程写入文件
#一个进程读取文件并输出
import
multiprocessing
import
time
def
write():
str=
'abcdefghijklmnopqrstuvwxyz'
with
open
(
'a.txt'
,
'w'
)
as
f:
for
ch
in
str:
f.write(
'%c%s'
% (ch,
'
\n
'
))
f.flush()
time.sleep(
1
)
def
read():
with
open
(
'a.txt'
,
'r'
)
as
f:
while True
:
str=f.read()
print
(str)
#不能判断26,因为有换行符
# if len(str)==26:
# break
#f.seek(0)表示从文件开始位置读取
# f.seek(0)
time.sleep(
2
)
if
__name__==
'__main__'
:
pw=multiprocessing.Process(
target
=write)
pr=multiprocessing.Process(
target
=read)
pw.start()
pr.start()
is_alive()
方法
如果
p
仍运行,返回
True
join([timeout])
方法
等待子进程
p
终止后再向下执行。
timeout
是可选的超时期限。进程可以被连接无数次,但如果连接自身则会出错。
run()
方法
进程启动时运行的方法(进程任务!)。默认情况下,会调用传递给
Process
构造函数的
target
。定义进程的另一种方法是从
Process
类继承并重新实现
run()
方法。
start()
方法
启动进程,并调用该子进程的
run()
方法。
terminate()
方法
强制终止进程。如果调用此函数,进程立即被终止,同时不会进行任何清理工作。如果进程创建了它自己的子进程,这些进程都将变为僵尸进程。如果进程保存了一个锁定或通过进程间通信被调用,那么终止它可能会导致死锁,或
io
崩溃。
authkey
属性
进程的身份验证键。除非显示设定,这是由
os.urandom()
函数生成的
32
位字符的字符串。其用途是为涉及网络连接的底层进程间通信提供安全性。
daemon
属性
一个
boolean
标志,指示进程是否是后台进程。后台进程无法创建自己的新进程。
daemon
的值必须再
start()
函数启动进程之前设置。
exitcode
属性
进程的整数退出码,如果进程仍在运行,其值为
None,
如果为负值,
-N
表示进程由信号
N
所终止。
name
属性
pid
属性
进程的整数进程
id
Queue(maxsize)
创建共享的进程队列。
maxsize
是队列中允许的最大项数。可省略,省略后表示大小无限制。
cancel_join_thread()
close()
empty()
full()
get([block[,timeout]])
get_nowait()
join_thread()
put(item[,block[,timeout]])
put_nowait(item)
qsize()
练习
2-1
#一个简单的使用队列在多个线程通信
#
from
multiprocessing
import
Process,Queue
import
codecs
import
time
def
write(q):
list=[
'你好'
,
'我好'
,
'他也好'
]
with
codecs.open(
'a.txt'
,
'w'
,
'utf-8'
)
as
f:
for
str
in
list:
f.write(
''
.join([str,
'
\n
'
]))
q.put(str)
time.sleep(
2
)
def
read(q):
while True
:
str=q.get()
print
(str)
if
__name__==
'__main__'
:
q=Queue()
pw=Process(
target
=write,
args
=(q,))
pr=Process(
target
=read,
args
=(q,))
pw.start()
pr.start()
JoinableQueue(maxsize)
创建可连接的共享进程队列,与
Queue
类似,但队列允许项目的使用者通知生产者,项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的
练习
2-1
中,由于
read
方法是死循环,因此主进程结束后,程序被挂起;可使用
JoinableQueue+
将消费进程设为守护进程的方式解决无意义的挂起问题。
练习
3-1
import
multiprocessing
import
time
def
producer(material,q):
for
str
in
material:
q.put(str)
print
(
'生产者将数据%s放入队列'
% str)
# time.sleep(1)
def
consumer(q):
while True
:
str=q.get()
print
(
'消费者消费一个数据%s'
% str)
#通知生产者已消费一个数据
q.task_done()
if
__name__==
'__main__'
:
list=[
'一'
,
'二'
,
'三'
]
q=multiprocessing.JoinableQueue()
pc=multiprocessing.Process(
target
=consumer,
args
=(q,))
#由于消费者进程是死循环,因此将其设置为守护进程
pc.daemon=
True
pc.start()
producer(list,q)
#由于pc是守护进程,为防止主进程结束时pc尚未执行完毕,因此调用队列q的join方法阻塞,
#等待所有数据均被处理(调用task_done()方法)后,再结束pc
q.join()
print
(
'主进程将执行结束'
)
练习
3-2
多个消费进程一起处理消息队列中的数据
import
multiprocessing
import
time
import
os
def
inp(p):
while True
:
str = p.get()
print
(
"%s--%s"
% (os.getpid(),str))
p.task_done()
time.sleep(
1
)
def
out(list,p):
for
str
in
list:
p.put(str)
print
(
'put a str(%s) into Queue'
% str)
if
__name__==
'__main__'
:
list=[
'aaa'
,
'bbb'
,
'ccc'
]
p=multiprocessing.JoinableQueue()
#创建两(多)个消费进程,一起处理消息队列中的数据
proc=multiprocessing.Process(
target
=inp,
args
=(p,))
proc.daemon=
True
proc2=multiprocessing.Process(
target
=inp,
args
=(p,))
proc2.daemon=
True
proc.start()
proc2.start()
out(list,p)
p.join()
输出结果:
put a str(aaa) into Queue
put a str(bbb) into Queue
put a str(ccc) into Queue
14996--aaa
4976--bbb
14996--ccc
由上可见,多个消费进程先到先得,多个消费进程一同处理一份消息队列中的数据
总的规则:发送数量少的大对象比发送数量多的小对象要好
在某些应用中,生产者需要通知消费者,它们不再生产任何项目而且应该关闭。为此,编写的代码中应该使用标志(
sentinel
)——指示完成的特殊值。下面的例子使用
None
作为标志说明这个概念:
import
multiprocessing
import
os
def
cons(q):
while True
:
str=q.get()
if
str
is None
:
break
print
(
'%s--%s'
% (os.getpid(),str))
def
prod(list,q):
for
str
in
list:
q.put(str)
if
__name__==
'__main__'
:
q=multiprocessing.Queue()
pc=multiprocessing.Process(
target
=cons,
args
=(q,))
pc.start()
list=[
'xxx'
,
'yyy'
,
'zzz'
]
prod(list,q)
#打一个值为None的标记,消费进程接收None后,跳出死循环,终止子进程
q.put(
None
)
#主进程等待子进程结束
pc.join()
但上面的例子只适合一个消费进程的情况,如果有多个消费进程,需要为每个消费进程单独打标记,才能让每个子进程正常结束,非常麻烦,解决的办法就是管道
task_done()
使用者使用此方法发出信号,表示
get()
方法返回的项目已经被处理。如果调用此方法的次数大于从队列中删除的项目数量,将引发
ValueError
异常
join()
生产者使用此方法进行阻塞,直到队列中的所有项目均被处理。阻塞将持续到为队列中的每个项目均调用
task_done()
方法为止
Pipe([duplex])
在进程之间创建一条管道,并返回元组(
conn1,conn2
),其中
conn1
和
conn2
是表示管道两端的
Connection
对象。默认情况下,管道是双向的。如果
duplex
值为
False
,
conn1
只能用于接收,而
conn2
只能用于发送。必须在创建和启动使用管道的
Process
对象之前调用
Pipe()
方法。
Pipe()
方法返回的
Connection
对象的实例具有以下方法和属性
注意理解下面两个示例中
Connection
对象的
input
和
output
input
:将数据放入管道
output
:从管道中取出
简单来说,就是
a
发送,
b
接收,
b
发送,
a
接收,但实际仍是一个
Connection
,区别指示接收的顺序不同
练习
4-1
import
multiprocessing
def
cons(pipe):
output_p, input_p = pipe
# 由于消费端不需要向管道放入数据,因此关闭
input_p.close()
while True
:
try
:
item = output_p.recv()
print
(item)
# 如果生产端关闭管道,则消费端会接收到EOFError异常,如出现此异常则表示
# 工作已结束,可以跳出死循环并结束子进程了
except
EOFError
:
break
print
(
'consumer done!'
)
def
prod(list, input_p):
for
item
in
list:
'''
向管道中放入数据
'''
input_p.send(item)
if
__name__ ==
'__main__'
:
list = [
'hello'
,
'ok'
,
'welcome'
]
output_p, input_p = multiprocessing.Pipe()
proc = multiprocessing.Process(
target
=cons,
args
=((output_p,input_p),))
'''
启动消费进程,让其等待处理数据
'''
proc.start()
'''
output_p用不到,因此关闭
'''
output_p.close()
'''
将数据放入管道
,
'''
prod(list, input_p)
'''
数据全部放入管道后,可以将
input_p关闭了
'''
input_p.close()
'''
主进程等待消费进程处理完毕
'''
proc.join()
练习
4-2
import
multiprocessing
import
os
import
codecs
def
write(pipe):
output_p, input_p = pipe
input_p.close()
while True
:
try
:
item = output_p.recv()
with
codecs.open(
'a.txt'
,
'a'
,
'utf-8'
)
as
f:
f.write(
'%s
\n
'
% item)
f.flush()
print
(item)
except
EOFError
:
break
def
suplly(list,input_p):
for
item
in
list:
input_p.send(item)
if
__name__==
'__main__'
:
output_p,input_p=multiprocessing.Pipe()
proc=multiprocessing.Process(
target
=write,
args
=((output_p,input_p),))
proc.start()
output_p.close()
suplly([
'中国'
,
'人民'
,
'万岁'
],input_p)
input_p.close()
proc.join()
close()
fileno()
poll()
recv()
recv_bytes([maxlength])
recv_bytes_into(buffer[,offset])
send()
send_bytes(buffer[,offset[,size]])