Python创建进程的两种方式

1.多进程

由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分需要使用进程.Python提供了非常好的多进程包multiprocessing,只需要定义一个函数,Python会完成其他所有事情.借助这个包,可以轻松完成从单进程到并发执行的转换.multiprocessing支持子进程,通信和共享数据,执行不同形式的同步,提供process,queue,pipe,lock等组件。

multiprocessing包是Python中的多进程管理包.与threading.Thread类似,它可以利用multiprocessin.Process对象来创建一个进程.该进程可以运行Python程序内部编写的函数.该Process对象与Thread对象的用法相同,也有start(),run(),join的方法,

此外multiprocessing包中也有lock/Event/Semophore/Condition类(这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致.所以,multiprocessing的很大一部分与threading使用同一套API,只不过换到多进程的情境。

在使用这此共享API的时候,我们要注意以下几点:

  • 在UNIX平台上,当某个进程终结之后,该进程需要被父进程调用wait,否则进程成为僵尸进程。所以,有必要对每个Process对象调用join()方法(实际上等同于wait).对于多线程来说,由于只有一个进程,所以不存在此必要性
  • multiprocessing提供了threading包中没有的IPC(比如Pipe和Queue),效率上更高。应优先考虑Pipe和Queue,避免使用lock/event/semaphore/condition等同步(因为它们占据的不是用户进程的资源)
  • 多进程应该避免共享资源。在多线程中,比较容易使用共享资源,比如使用全局变量或者传递参数。在多进程情况下,由于每个进程有自己独立的内存空间,以以方法并不合适。此时可以共享内存和mangaer的方法共享资源。但这样做提高了程序的复杂度,并因为同步需要而降低了程序的效率。

ProcessPID中保存有PID,如果进程还没有start(),即PID为None

在windows系统下,需要注意的是要想启动一个子进程,必须加上那句if__name__==“main”,进程相关的要写在这句下面.

2.实例分析
[root@node2 multiprocess]# cat multi-process.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process    #引用进程模块
import time
def f(name):
    time.sleep(1)
    print('hello',name,time.ctime())
 
if __name__=='__main__':
    p_list=[]
    for i in range(3):
        p = Process(target=f, args=('reid',))  #创建一个进程对象,再传入一个函数f为参数
        p_list.append(p)
        p.start()
    for p in p_list:
        p.join()
    print('end')
[root@node2 multiprocess]# python3 multi-process.py  #程序中有一个主进程,三个子进程,进程之间是独立运行的,互不干扰
hello reid Sun Jun 10 10:13:57 2018
hello reid Sun Jun 10 10:13:57 2018
hello reid Sun Jun 10 10:13:57 2018
end

类式调用

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 multiprocess]# cat muti-process-class.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process
import time
 
class MyProcess(Process):  #继承multiprocessing下的Process
    def __init__(self):
        super(MyProcess,self).__init__()  #继承父类的init方法
 
    def run(self):
        time.sleep(1)
        print('hello',self.name,time.ctime())  
        #三个进程同时打印,self.name本身有值,进程对象下的一个属性,进程名,如进程1,进程2等,也可以赋值,在实例化对象时,传入一个参数
 
if __name__=='__main__':
    p_list=[]
    for i in range(3):
        p = MyProcess()      #进程对象
        p.start()            #启动
        p_list.append(p)
 
    for p in p_list:
        p.join
 
    print('end')
[root@node2 multiprocess]# python3 muti-process-class.py
end
hello MyProcess-1 Sun Jun 10 11:43:24 2018
hello MyProcess-3 Sun Jun 10 11:43:24 2018
hello MyProcess-2 Sun Jun 10 11:43:24 2018

父进程与子进程间的关系

[root@node2 multiprocess]# cat par-chil.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process
import os
import time
def info(title):
    print(title)             #传输什么,打印什么
    print('module name: ',__name__)          #__name__是main
    print('parent prcess: ',os.getppid())     #打印父进程号
    print('process id: ', os.getpid())        #打印进程号
 
def f(name):
    info('\033[31;1mfunction f\033[0m')
    print('hello',name)
 
if __name__=='__main__':
    info('\033[32;1mmain process line \033[0m')  #传入参数,执行info函数
    time.sleep(3)
    p = Process(target=info,args=('bob',))  #创建子进程
    p.start()
    p.join()
[root@node2 multiprocess]# python3 par-chil.py
main process line
module name:  __main__   主进程
parent prcess:  13838
process id:  14521       ###
bob
module name:  __main__   子进程
parent prcess:  14521    ###
process id:  14522
3.进程通信和数据共享

分析:线程可以共享数据,进程之间实现通信的方法是使用pipe和queue

(1)、Queue

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 multiprocess]# cat que.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process,Queue
def f(q):
    q.put([42,2,'hello'])
 
if __name__=='__main__':
    q = Queue()         #进程队列
    p_list=[]
    for i in range(3):
        p = Process(target=f,args=(q,)) #q作为参数由父进程传给子进程,因为正确情况下,父进程和子进程不能通信
        p_list.append(p)
        p.start()
    print(q.get())
    print(q.get())
    print(q.get())
    for i in p_list:
            i.join()
[root@node2 multiprocess]# python3 que.py
[42, 1, 'hello']
[42, 0, 'hello']
[42, 2, 'hello']

确认def f中的q和p = Process(target=f,args=(q,i))中的q

[root@node2 multiprocess]# cat que.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process,Queue
def f(q):
    q.put([42,2,'hello'])
    print('subprocess q id: ', id(q))   ###id一样表示是共享的,不一样表示copy的
 
if __name__=='__main__':
    q = Queue()
    p_list=[]
    print('main q id: ', id(q))  ###
 
    for i in range(3):
        p = Process(target=f,args=(q,))
        p_list.append(p)
        p.start()
    print(q.get())
    print(q.get())
    print(q.get())
    for i in p_list:
            i.join()
[root@node2 multiprocess]# python3 que.py
main q id:  140394463540392
subprocess q id:  140394463540392   #windows测试可能不一样
[42, 2, 'hello']
subprocess q id:  140394463540392
subprocess q id:  140394463540392
[42, 2, 'hello']
[42, 2, 'hello']

(2)、Pipe

分析:父进程处理阻塞状态等待接收,子进程进行发送数据

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 multiprocess]# cat pipes.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process,Pipe
def f(conn):
    conn.send([42,None,'hello'])
    conn.close()
 
if __name__=='__main__':
    parent_conn,child_conn = Pipe()  #父进程和字进程的通道
    p = Process(target=f,args=(child_conn,))  
    #把子进程的通道作为参数传入子进程,通过函数f可以进行send和reveice,而且在主进程也有parent conn                       
    p.start()                   #启动一个子进程
    print(parent_conn.recv())   #父进程在等待接收(阻塞),直到子进程执行f函数时,有个子进程的管道进行conn.send发送数据,parent_conn可以接收
    p.join()
[root@node2 multiprocess]# python3 pipes.py
[42, None, 'hello']

(3)、Manager

描述: 数据共享
[root@node2 multiprocess]# cat manager.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process, Manager
def f(d,l,n):     #d是字典,l是列表,n是i一个0-9的值
    d[n] = '1'    #d实际是manager创建的
    d['2'] = 2
    d[0.25] = None
#字典d,当一个进程进入后,操作后有三个键值对,第二个进程进入后,d,l是一样的,会被覆盖掉,如果把n修改成1就变成三个键值对,
#因为第一个进程进入时,字典是空的,会首先创建三个键值对,第二个进程进入时,会进行覆盖,因为字典是共用的,d[1] = 1都一样,
#所以10个进程走完后,三个键值对不还是一样
    l.append(n)   #往列表中添加值
 
if __name__=='__main__':
    with Manager() as manager:  ##manager = manager()
        d = manager.dict()   #创建一个空字典实现进程之间共享
 
        l = manager.list(range(5))  #创建一个从0到4的列表
        p_list = []
        for i in range(10):         #创建10个进程
            p = Process(target=f,args=(d,l,i))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()
        print(d)
        print(l)
[root@node2 multiprocess]# python3 manager.py
{0: '1', '2': 2, 0.25: None, 3: '1', 5: '1', 1: '1', 6: '1', 4: '1', 7: '1', 8: '1', 2: '1', 9: '1'} #三组键值对
[0, 1, 2, 3, 4, 0, 3, 5, 6, 1, 4, 7, 8, 2, 9]  ##0,1,2,3,4是初始时就有

分析:主进程和子进程是否一致

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:579817333 
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
[root@node2 multiprocess]# cat manager.py
#!/usr/local/python3/bin/python3
from multiprocessing import Process, Manager
def f(d,l,n):
    d[n] = '1'
    d['2'] = 2
    d[0.25] = None
    l.append(n)
    print('sub',id(d))            #########
 
if __name__=='__main__':
    with Manager() as manager:
        d = manager.dict()
 
        l = manager.list(range(5))
        p_list = []
 
        print('main',id(d))         #######
        for i in range(10):
            p = Process(target=f,args=(d,l,i))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()
        print(d)
        print(l)
 
[root@node2 multiprocess]# python3 manager.py   ##结果windows不一样,linux中是一样的
main 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
sub 140423045960872
{0: '1', '2': 2, 0.25: None, 3: '1', 2: '1', 4: '1', 7: '1', 8: '1', 5: '1', 1: '1', 9: '1', 6: '1'}
[0, 1, 2, 3, 4, 0, 3, 2, 4, 7, 8, 1, 5, 6, 9
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值