一、什么是多进程
相信看过我其他博客的同学已经对多线程和多进程有一个简单的了解了,下面我们简单说一下多进程。我们知道在进行较多的I/O操作时候,比如socket server之类的可以用到多线程,那么什么时候用多进程呢?我们在进行大量的密集运算时候就要用到多进程。下面我们讲解一下多进程的相关知识:
(1)启动多进程,并在多进程中启动多线程
#启动多进程
import multiprocessing #多进程
import time,threading #多线程
def thread_run():
print(threading.get_ident()) #打印当前线程ID
def f(name):
time.sleep(2)
print('hello',name)
t=threading.Thread(target= thread_run,) #在多进程调用的函数中创建一个多线程
t.start()
if __name__ == '__main__': #区分主动执行脚本还是从别的代码里导入,如果主动执行下面的就执行(在window中需要加入这句话)
for i in range(10): #启动10个多进程
p=multiprocessing.Process(target=f,args= ('我是%s'%i,))
p.start()
p.join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
执行之后会启动10个多进程,每个多进程中都会启动一个多线程,并打印该线程的id,结果如下:
(2)每一个子进程都是由父进程启动的
我们需要知道,每一个子进程都是由父进程启动的。下面我们来通过获取进程id的方式来证明一下:
#我们这里父进程是:pycharm本身 由pycharm启动了子进程
from multiprocessing import Process
import os
def info(title):
print(title)
print('module name:',__name__) #获取__name__名称
print('parent process:',os.getppid()) #得到父进程id
print('process id:',os.getpid()) #得到自己id
print('\n\n')
def f():
info('\033[31;1mfunction f\033[0m') #子进程调用info()
if __name__ == '__main__':
info('\033[32;1mmain process line\033[0m') #父进程调用info()
p=Process(target= f,) #自动多进程
p.start()
p.join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
我们分别用父进程和子进程来调用函数info(),打印自己的和父进程的id,结果如下:
观察一下,父进程是黄色的,它的父进程id是16624,这个是pycharm本身,它的id是13624,子进程是红色的,它的父进程id是13624,也就父进程,它本身的id是12444,所以可以说是父线程创建了子线程。
(3)进程间的通信
大家都知道一个进程内的线程之间可以进行数据通信,但是两个进程不能直接通信,就比如我们不能利用腾讯视频来买淘宝的东西,那么我们怎么才能实现进程之间的数据传递和数据修改呢??
下面我简单介绍一下3个方法来实现进程间的数据通信:
Queues:实现两个进程之间的数据传递
Pipes:管道形式数据传递,建立一个管道通讯
Managers:实现两个进程的数据共享(可以修改数据,不仅仅是传递数据)
先说一下队列方法(Queues):
from multiprocessing import Process ,Queue #导入Queue模块
def f(q1):
q1.put(['hello',42]) #在子进程中把数据['hello',42]放入队列中
if __name__ == '__main__':
q=Queue() #启动一个进程的队列
p=Process(target= f,args= (q,)) #在启动子进程时候,将进程的队列q赋值进去
p.start()
print(q.get()) #父进程从队列中取数据,实现两个进程之间的数据通讯
p.join()
1
2
3
4
5
6
7
8
9
10
11
结果是:
然后介绍一下Pipes方法,就是在进程之间生成一个管道进行数据传递。
from multiprocessing import Process ,Pipe #导入Pipe模块
def f1(conn):
conn.send([42,'hello']) #子进程发送数据
print('from parent:',conn.recv()) #子进程接收父进程的数据
conn.close()
if __name__ =='__main__':
parent_conn,child_conn=Pipe() #生成管道的两头,一个父进程一个子进程
p=Process(target= f1,args=(child_conn,)) #创建一个子进程
p.start()
print(parent_conn.recv()) #父进程这里接收子进程发送的数据
parent_conn.send('你好') #父进程发送数据给子进程
p.join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
结果是:
最后我们说明Managers这个方法,可以进行进程之间的数据修改。
from multiprocessing import Process ,Manager #导入Manager方法
import os
def f2(d,l):
d[os.getpid()]=os.getpid() #10个进程都在修改字典,键和值都为每个子进程的id
l.append(os.getpid()) #10个进程都在扩充列表
print(l)
if __name__ == '__main__':
with Manager() as manager:
d=manager.dict() #manager中的生成一个可在多个进程中传递、共享数据的字典
l=manager.list(range(5)) #manager中的生成一个可在多个进程中传递、共享数据的列表
p_list=[]
for i in range(10): #创建10个子进程
p=Process(target=f2,args= (d,l))
p.start()
p_list.append(p)
for res in p_list : #等待所有进程执行完毕
res.join()
print(d)
print(l)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
结果是:
可以发现进程之间可以进行数据修改。
(4)进程池
进程池是防止启动进程过多,系统负荷大,而设置的。看一个例子:
from multiprocessing import Process,Pool #导入进程池
import time,os
def Foo(i):
time.sleep(2)
print('到了2s')
return i+100
def Bar(arg):
print('结果:',arg)
if __name__ == '__main__':
pool=Pool(processes= 5) #允许进程池同时放入5个进程
for i in range(10): #10个进程都启动 但是一次只能运行5个
#pool.apply(func= Foo,args=(i,)) #串行执行进程,一次执行1个进程
pool.apply_async(func= Foo,args=(i,),callback= Bar) #并行执行进程,一次5个,callback回调 Foo执行完就会执行Bar
print('end')
pool.close()
pool.join() #等待进程池中的进程执行完毕 必须先close() 在join()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
结果是:
可以利用进程池来限制每次执行进程的数量,防止电脑负荷过大。
---------------------
作者:哎呀姜
来源:CSDN
原文:https://blog.csdn.net/weixin_42898819/article/details/81811514
版权声明:本文为博主原创文章,转载请附上博文链接!