只有一个子进程:
# 多线程的实现
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=('test1',))
print('Child process will start')
p.start()
p.join()
print('Child process end')
p就是创建的子进程,里面两个参数分别是子进程要实现的函数和args(参数)
通过p.start()来开始
打印:
Parent process 3116.
Child process will start
Run child process test1 (1580)..
Child process end
getpid()是获取进程的标号的,每个进程都会有一个标号
进程池:
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 %.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')
打印:
Parent process 7148.
Waiting for all subprocesses done...
Run task 0 (956)
Run task 1 (22768)
Run task 2 (5188)
Run task 3 (20580)
Task 2 runs 1.16 seconds.
Run task 4 (5188)
Task 0 runs 2.00 seconds.
Task 3 runs 2.51 seconds.
Task 1 runs 2.87 seconds.
Task 4 runs 1.79 seconds.
All subprocesses done
我们解读一下:先是主进程开始,然后进入子进程task0-4是立即执行的,然后因为task2执行的比较快,所以他就会在task4之前打印出来1.16s,如果我们不加上p.join():
Parent process 15156.
Waiting for all subprocesses done...
All subprocesses done
就没有子进程了,所以join就是会等待子线程全部执行完才会结束
p=Pool(4)表示开启4个进程
进程之间的通讯
#线程之间的通讯
from multiprocessing import Process,Queue
import os,time,random
def write(q):
print('Process to write:%s'% os.getpid())
for value in ['mason','mike','lucy']:
print('Put %s to queue'%value)
q.put(value)
time.sleep(random.random())
def read(q):
print('Process to read:%s'%os.getpid())
while True:
value=q.get(True)
print('Get %s from queue.'%value)
if __name__=='__main__':
q=Queue()
pw=Process(target=write,args=(q,))#写操作的子进程
pr=Process(target=read,args=(q,))#读操作的子进程
pw.start()
pr.start()
pw.join()
pr.terminate()
这是设置了两个进程,一个用来写一个用来读,用一个multiprocessing里面的Queue来装数据。注意以下几点:
(1) 在实例化Queue类,可以传递最大消息数,如q = Queue(5),这段代码是指只允许消息队列中最大有5个消息数据。如果不加最大消息数或数量为负值,则表达不限制数量直到占满内存;
(2) Queue.qsize():返回当前队列包含的消息数量;
(3) Queue.empty():如果队列为空,返回True,反之False ;
(4) Queue.full():如果队列满了,返回True,反之False;
(5) Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出”Queue.Empty”异常;
2)如果block值为False,消息列队如果为空,则会立刻抛出”Queue.Empty”异常;
(6) Queue.get_nowait():相当Queue.get(False);
(7) Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出”Queue.Full”异常;
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出”Queue.Full”异常;
(8) Queue.put_nowait(item):相当Queue.put(item, False);
(9)pr.terminate()是关闭进程的意思,但是它又不会马上就关闭:
p.terminate() # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
print(p.is_alive()) # True
time.sleep(0.1)
print(p.is_alive()) # False
还可以写成:
def write(q):
print('Process to write:%s'% os.getpid())
for value in ['mason','mike','lucy']:
print('Put %s to queue'%value)
q.put(value)
time.sleep(1)
def read(q):
print('Process to read:%s'%os.getpid())
while not q.empty():
value=q.get(True)
print('Get %s from queue.'%value)
time.sleep(1)
这样就需要两个进程sleep的时间相同,因为我们while的条件的是队列不空
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:
RuntimeError: Queue objects should only be shared between processes through inheritance.
# pool进程通讯
from multiprocessing import Manager, Pool
import time
def write(q):
for i in ["A", "B", "C", "D", "E"]:
print("向队列中添加%s" % i)
q.put(i)
time.sleep(1)
def read(q):
while not q.empty():
print("从队列中取出的值是%s" % q.get())
time.sleep(1)
if __name__ == '__main__':
q = Manager().Queue()
pool = Pool(2)
pool.apply_async(write, args=(q,))
pool.apply_async(read, args=(q,))
pool.close()
pool.join()
print("数据通信完毕")
至于为什么使用pool线程通讯一定要multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),请参考:
https://www.cnblogs.com/zhiyong-ITNote/p/7204722.html?utm_source=itdadao&utm_medium=referral(这个文章里面还有线程跟进程的区别,请认真阅读)
多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。
其他参考文章: