一、Python多进程模块Python中的多进程是通过multiprocessing包实现的,类似于多线程threading.Thread。它可以使用multiprocessing.Process对象来创建进程对象。这个进程对象的方法和线程对象几乎一样。有start()、run()、join()等方法,其中一个方法是不同的。Thread线程对象中的daemon线程方法是setDeamon,Process进程对象的守护进程是通过设置daemon属性来实现的。下面说说Python多进程的实现方法,类似于多线程2.Python多进程实现方法一frommultiprocessingimportProcessdeffun1(name):print('测试%s多进程'%name)if__name__=='__main__':process_list=[]foriinrange(5):#开启5个子进程执行fun1functionp=Process(target=fun1,args=('Python',))#实例化进程对象p.start()进程列表。append(p)foriinprocess_list:p.join()print('endtest')结果测试Python多进程测试Python多进程测试Python多进程测试Python多进程测试Python多进程测试Pythonmulti-processendtestProcessfinishedwithexitcode0上面的代码启动了5个子进程来执行函数。我们可以观察同时打印的结果。这里实现了真正的并行操作,即多个CPU同时执行任务。我们知道进程是python中最小的资源分配单元,也就是进程中间的数据。内存不共享。每次启动一个进程,都要独立分配资源,访问的数据也要复制,所以启动和销毁进程的代价是比较大的,所以在实际中使用多进程,应该根据服务器的配置。3.Python多进程实现方法2大家还记得python多线程的第二种实现方法吗?它是通过类继承的方式实现的,和python多进程的第二种实现方式一样frommultiprocessingimportProcessclassMyProcess(Process):#InheritProcessclassdef__init__(self,name):super(MyProcess,self).__init__()self.name=namedefrun(self):print('Test%smulti-process'%self.name)if__name__=='__main__':process_list=[]foriinrange(5):#开启5个子进程执行fun1functionp=MyProcess('Python')#实例化进程对象p.start()process_list.append(p)foriinprocess_list:p.join()print('endtest')result测试Python多进程测试Python多进程测试Python多进程测试Python多进程测试Python多进程测试Python多进程结束测试Processfinishedwithexitcode0effectandOnewaysame.我们可以看到,Python多处理的实现和多线程的实现几乎是一样的。Process类的其他方法构造方法:Process([group[,target[,name[,args[,kwargs]]]]])group:线程组target:要执行的方法name:进程名args/kwargs:参数传入方法实例方法:is_alive():返回进程是否运行,bool类型。join([timeout]):阻塞当前上下文的进程,直到调用此方法的进程终止或达到指定的超时时间(可选参数)。start():进程就绪,等待CPU调度run():strat()调用run方法,如果实例进程中没有指定target,则本星执行默认的run()方法。terminate():无论任务是否完成,立即停止工作进程属性:daemon:与线程setDeamon功能相同name:进程名pid:进程号关于join,daemon的使用和python多线程一样,所以我不会在这里重复它。可以看之前的python多线程系列文章。4、Python多线程通信过程是系统独立调度和分配系统资源(CPU、内存)的基本单元。这些过程彼此独立。每启动一个新进程,就相当于克隆了一次数据。主进程中的数据修改不能影响主进程中的数据,不同子进程之间的数据不能共享。这是多进程和多线程在使用上最明显的区别。但是在Python多进程中间是孤立的吗?当然不是,python也提供了多种方法来实现多个进程之间的通信和数据共享(可以修改一条数据)。进程对队列QueueQueue在多线程中也有提到,用于生产者消费者模式,是线程安全的,是生产者和消费者之间的数据管道。在python多进程中,其实就是进程之间的数据管道,实现进程通信。frommultiprocessingimportProcess,Queuedeffun1(q,i):print('子进程%s开始放数据'%i)q.put('我%s通过Queue通信'%i)if__name__=='__main__':q=Queue()process_list=[]foriinrange(3):p=Process(target=fun1,args=(q,i,))#注意q对象必须传递给我们的方法想在args中执行,让子进程可以使用Queue与主进程通信p.start()process_list.append(p)foriinprocess_list:p.join()print('主进程获取Queue数据')print(q.get())print(q.get())print(q.get())print('endtest')resultsubprocess0开始putdatasubprocess1开始putdatasubprocess2开始putdatamainprocessgetQueuedataIam0ThroughQueuecommunication,Iam1通过Queuecommunication,Iam2通过Queuecommunication,testProcessfinishedwithexitcode0以上代码结果可以看出我们的主进程可以获取到put中的数据子进程通过队列,并实现我进程间通信通信。PipelinePipelinePipeline和Queue的功能大致相同,同样实现了进程间通信。让我们看看下面如何使用它们。frommultiprocessingimportProcess,Pipedeffun1(conn):print('Subprocesssendsamessage:')conn.send('Hellomainprocess')print('Sub-processacceptmessage:')print(conn.recv())conn.close()if__name__=='__main__':conn1,conn2=Pipe()#关键点,pipe实例化生成双向管道p=Process(target=fun1,args=(conn2,))#conn2传递给子进程p.start()print('主进程接受消息:')print(conn1.recv())print('主进程发送消息:')conn1.send("Hellosub-process")p.join()print('Endtest')结果主进程收到消息:子进程发送消息:子进程收到消息:YouGood主进程主进程发送一个message:hellosub-processendtestProcessfinishedwithexitcode0上面可以看到主进程和子进程可以互相发送消息ManagersQueue和Pipe只实现数据交互,不实现数据共享,即一个进程更改数据另一个过程。这么长时间使用ManagersfrommultiprocessingimportProcess,Managerdeffun1(dic,lis,index):dic[index]='a'dic['2']='b'lis.append(index)#[0,1,2,3,4,0,1,2,3,4,5,6,7,8,9]#print(l)if__name__=='__main__':withManager()asmanager:dic=manager.dict()#注意字典的声明方式,不能直接通过{}来定义l=manager.list(range(5))#[0,1,2,3,4]process_list=[]foriinrange(10):p=Process(target=fun1,args=(dic,l,i))p.start()process_list.append(p)forresinprocess_list:res.join()print(dic)print(l)结果:{0:'a','2':'b',3:'a',1:'a',2:'a',4:'a',5:'a',7:'a',6:'a',8:'a',9:'a'}[0,1,2,3,4,0,3,1,2,4,5,7,6,8,9]可以看到主进程定义了一个字典和一个列表。在子进程中,可以添加和修改字典的内容,向链表中插入新的数据,实现进程间的数据共享,即可以共同修改相同的数据5.进程池进程池维护一个进程顺序。使用时去进程池中获取一个进程。如果进程池序列中没有可用进程,程序将一直等待,直到进程池中有可用进程。直到。也就是说,有几个固定的进程可以使用。进程池中有两个方法:apply:同步,一般不用apply_async:asynchronousfrommultiprocessingimportProcess,Poolimportos,time,randomdeffun1(name):print('Runtask%s(%s)...'%(name,os.getpid()))start=time.time()time.sleep(random.random()*3)end=time.time()print('任务%s运行%0.2f秒。'%(name,(end-start)))if__name__=='__main__':pool=Pool(5)#创建一个包含5个进程的进程池foriinrange(10):pool.apply_async(func=fun1,args=(i,))pool.close()pool.join()print('endtest')result运行任务0(37476)...运行任务1(4044)...任务0运行0.03秒。运行任务2(37476)...运行任务3(17252)...运行任务4(16448)...运行任务5(24804)...任务2运行0.27秒。运行任务6(37476)...任务1运行0.58秒。运行任务7(4044)...任务3运行0.98秒。运行任务8(17252)...任务5运行1.13秒。运行任务9(24804)...任务6运行1.46秒.任务4运行2.73秒。任务8运行2.18秒。任务7运行2.93秒。任务9运行2.93秒。结束对Pool对象的测试调用join()方法将等待所有子进程完成执行。在调用join()之前,必须先调用close()。调用close()后,不能继续添加新的Processes。processpoolmap方法案例来源于网络,如有侵权请告知,谢谢,因为在网上看到这个例子,觉得还不错,这里就不写案例了,这个案例importosimportPILfrommultiprocessingimportPoolfromPILimportImageSIZE=(75,75)SAVE_DIRECTORY=\'thumbs\'defget_image_paths(folder):return(os.path.join(folder,f)forfinos更有说服力.listdir(folder)if\'jpeg\'inf)defcreate_thumbnail(filename):im=Image.open(filename)im.thumbnail(SIZE,Image.ANTIALIAS)base,fname=os.path.split(filename)save_path=os.path.join(base,SAVE_DIRECTORY,fname)即时通讯。保存(保存路径)if__name__==\'__main__\':文件夹=os.path.abspath(\'11_18_2013_R000_IQM_Big_Sur_Mon__e10d1958e7b766c3e840\')os.mkdir(os.path.join(文件夹,SAVE_folds_DIRECTORY=)pathimage(getimages=image))=Pool()pool.map(creat_thumbnail,images)#重点,images是一个可迭代对象pool.close()pool.join()上面代码的主要工作是遍历传入的文件夹文件中的图片,生成一张一张的缩略图,并将这些缩略图保存到特定的文件夹中。在我的机器上,这个程序需要27.9秒来处理6000张图像。map函数不支持手动线程管理,但是让相关的调试工作变得异常简单。Map也可以用在爬虫领域。比如爬取多个url的内容,可以把url放到祖先中,然后传给执行函数。
