多进程
fork()
Unix/Linux/Mac操作系统都可以使用fork()
函数来创建子进程,分别在父进程和子进程内返回
os.fork() 会有两次返回值,分别是父进程和子进程的返回值
在父进程中,fork返回的值是子进程的PID;
子进程中,这个返回值为0
子进程应该是从调用fork()的地方开始执行代码
父子进程并不能确定执行顺序
import os # 导入os模块
print ('当前进程的ID是:%s' % os.getpid()) # os.getpid()返回的是进程的id不是线程
ID = os.fork() # 创建子进程,并返回进程的id,父进程返回的是子进程的id,子进程返回的是0
if ID == 0:
print ('这是子进程,ID是:%s。。父进程ID是:%s' % (os.getpid(), os.getppid()))
else:
print ('这是父进程,ID是:%s' % os.getpid())
结果:
当前进程的ID是:1064
这是父进程,ID是:1064
这是子进程,ID是:1065。。父进程ID是:1064
multiprocessing
multiprocessing
模块就是跨平台版本的多进程模块。multiprocessing
模块提供了一个Process
类来代表一个进程对象,创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process
实例,用start()
方法启动
Process类
1.1 构造方法
def __init__(self, group=None, target=None, name=None, args=(), kwargs={})
group:进程所属组,基本不用
target:进程调用对象(可以是一个函数名,也可以是一个可调用的对象(实现了__call__方法的类))
args:调用对象的位置参数元组
name:别名
kwargs:调用对象的关键字参数字典
1.2 实例方法
is_alive():返回进程是否在运行
start():启动进程,等待CPU调度
join([timeout]):阻塞当前上下文环境,直到调用此方法的进程终止或者到达指定timeout
terminate():不管任务是否完成,立即停止该进程
run():start()调用该方法,当实例进程没有传入target参数,stat()将执行默认的run()方法
1.3 属性
authkey:
daemon:守护进程标识,在start()调用之前可以对其进行修改
exitcode:进程的退出状态码
name:进程名
pid:进程
from multiprocessing import Process
import os
def run_proc(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run_proc, args=('test',))
print('Child process will start.')
p.start()
p.join()
print('Child process end.')
"C:\Program Files (x86)\Python36-32\python.exe" D:/python_work/PythonLearning/process.py
Parent process 2432.
Child process will start.
Run child process test (8992)...
Child process end.
Process finished with exit code 0
Pool
from multiprocessing import Pool
import os, time, random
def long_time_task(name):
print('Run task %s (%s)...' % (name, os.getpid()))
start = time.time()
time.sleep(random.random() * 3)
end = time.time()
print('Task %s runs %0.2f seconds.' % (name, (end - start)))
if __name__=='__main__':
print('Parent process %s.' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('Waiting for all subprocesses done...')
p.close()
p.join()
print('All subprocesses done.')
"C:\Program Files (x86)\Python36-32\python.exe" D:/python_work/PythonLearning/process.py
Parent process 8216.
Waiting for all subprocesses done...
Run task 0 (2884)...
Run task 1 (3572)...
Run task 2 (1428)...
Run task 3 (5964)...
Task 0 runs 1.24 seconds.
Run task 4 (2884)...
Task 3 runs 1.65 seconds.
Task 1 runs 1.82 seconds.
Task 2 runs 1.98 seconds.
Task 4 runs 0.91 seconds.
All subprocesses done.
join
阻塞当前进程,直到调用join方法的那个进程执行完,再继续执行当前进程
#encoding:utf-8
from multiprocessing import Process
import os, time, random
def r1(process_name):
for i in range(5):
print process_name, os.getpid() #打印出当前进程的id
time.sleep(random.random())
def r2(process_name):
for i in range(5):
print process_name, os.getpid() #打印出当前进程的id
time.sleep(random.random()*2)
if __name__ == "__main__":
print "main process run..."
p1 = Process(target=r1, args=('process_name1', ))
p2 = Process(target=r2, args=('process_name2', ))
p1.start()
p2.start()
p1.join()
#p2.join()
print "main process runned all lines..."
发现主线程只是等待p1完成了,就会向下执行,而不会等待p2是否完成。
所以使用多进程的常规方法是,先依次调用start启动进程,再依次调用join要求主进程等待子进程的结束。
进程通信
Process
之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing
模块包装了底层的机制,提供了Queue
、Pipes
等多种方式来交换数据。
Queue:
Queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递
class Queue.Queue(maxsize=0)
FIFO即First in First Out,先进先出。Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。
class Queue.LifoQueue(maxsize=0)
LIFO即Last in First Out,后进先出。与栈的类似,使用也很简单,maxsize用法同上
class Queue.PriorityQueue(maxsize=0)
构造一个优先队列。maxsize用法同上。
put(item[, block[, timeout]])
将item放入队列中。
- 如果可选的参数block为True且timeout为空对象(默认的情况,阻塞调用,无超时)。
- 如果timeout是个正整数,阻塞调用进程最多timeout秒,如果一直无空空间可用,抛出Full异常(带超时的阻塞调用)。
- 如果block为False,如果有空闲空间可用将数据放入队列,否则立即抛出Full异常
其非阻塞版本为put_nowait
等同于put(item, False)
get([block[, timeout]])
从队列中移除并返回一个数据。block跟timeout参数同put
方法其非阻塞方法为`get_nowait()`相当与get(False)
empty()
如果队列为空,返回True,反之返回False
from multiprocessing import Process, Queue
import os, time, random
# queue模块实现了多生产者,多消费者的队列。当 要求信息必须在多线程间安全交换,这个模块在 线程编程时非常有用 。
# Queue模块实现了所有要求的锁机制。
# 说了半天就是Queue模块主要是多线程,保证线程安全使用的。
# 这个类实现了三种类型的queue,区别仅仅在于进去和取出的位置。在一个FIFO(First In,First Out)队列中,先加先取。
# 在一个LIFO(Last In First Out)的队列中,最后加的先出来(操作起来跟stack一样)。priority队列,有序保存,优先级最低的先出来
# class queue.Queue(maxsize = 0)构造一个FIFO队列
#Queue.get(item, block=True, timeout=None): 从队列里取数据。
# 如果为空的话,blocking = False 直接报 empty异常。
# 如果blocking = True,就是等一会,timeout必须为 0 或正数。
# None为一直等下去,0为不等,正数n为等待n秒还不能读取,报empty异常。
#
# 写数据进程执行的代码:
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(2)
# 读数据进程执行的代码:
def read(q):
print('Process to read: %s' % os.getpid())
while True:
time.sleep(3)
value = q.get(block=True, timeout=None)
print('Get %s from queue.' % value)
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 启动子进程pr,读取:
pr.start()
# 等待pw结束:
pw.join()
# pr进程里是死循环,无法等待其结束,只能强行终止:
pr.terminate()
"C:\Program Files (x86)\Python36-32\python.exe" D:/python_work/PythonLearning/process.py
Process to write: 4940
Put A to queue...
Process to read: 8208
Put B to queue...
Get A from queue.
Put C to queue...
Get B from queue.
multiprocessing.Pipe([duplex])
返回2个连接对象(conn1, conn2),代表管道的两端,默认是双向通信.如果duplex=False,conn1只能用来接收消息,conn2只能用来发送消息.不同于os.open之处在于os.pipe()返回2个文件描述符(r, w),表示可读的和可写的
# -*- coding:utf-8 -*-
from multiprocessing import Process, Pipe
def proc1(pipe):
s = 'Hello,This is proc1'
pipe.send(s)
def proc2(pipe):
while True:
print("proc2 recieve:"+ pipe.recv())
if __name__ == "__main__":
pipe = Pipe()
p1 = Process(target=proc1, args=(pipe[0],))
p2 = Process(target=proc2, args=(pipe[1],))
p1.start()
p2.start()
p1.join()
p2.join(2) #限制执行时间最多为2秒
print('\nend all processes.')
p2.terminate()
"C:\Program Files (x86)\Python36-32\python.exe" D:/python_work/PythonLearning/processpipe.py
proc2 recieve:Hello,This is proc1
end all processes.
Process finished with exit code 0