当前位置: 首页 > 后端技术 > Python

Python爬虫进阶:进程

时间:2023-03-25 19:47:46 Python

进程介绍在python开发中,进程和线程是非常重要的。创建分布式爬虫,提高工作效率,离不开进程和线程。进程进程是程序在数据集上的动态执行过程。一个进程一般由三部分组成:程序、数据集和进程控制块。我们编写的程序是用来描述进程需要完成哪些功能以及如何完成;数据集是程序在执行过程中需要使用的资源;进程控制块用于记录进程的外部特征,描述进程执行变化,系统可以用来控制和管理进程,是系统感知到进程存在的唯一标志.多进程python实现多进程有两种方式,一种是os模块中的fork方法,一种是multiprocessing模块。两种方式的区别在于fork方式只支持Unix/Linux系统,不支持Windows,而且后一种方式是跨平台的。fork方法是专门用来实现多进程的。fork方法比较特殊。普通方法调用一次返回一次,而fork方法调用一次返回两次,因为操作系统将当前父进程复制到一个子进程中,两个进程几乎完全相同,所以fork方法在分别是父进程和子进程。子进程总是返回0。父进程返回子进程的id。os模块的getpid用于获取子进程id,getppid用于获取父进程id。看下面示例:[Python]纯文本视图__复制代码?0102030405060708091011121314importos`'''更多Python学习资料和源码教程资料可在群里免费获取821460695'''if__name__=`='__main__'`:print'currentProcess%sstart...'%(os.getpid())pid=os.fork()printpidifpid<0`:`print'errorinfork'elifpid=`=0`:print'我是子进程%s,我的父进程是%s'%(os.getpid(),os.getppid())else`:`print'我%s创建了一个子进程%s。%`(os.getpid(),pid)`返回结果如下:[Python]纯文本视图__复制代码?12345678#父进程currentProcess11989start...#子进程pid11990I11989创建了子进程11990.#子进程pidreturns00我是子进程11990我的父进程是11989描述进程对象的类Process。创建子进程时,只需要传入一个函数和函数参数即可创建创建一个Process实例,使用start()方法启动进程,join()方法实现进程间同步,看下面例子:【Python】纯文本view__复制代码?010203040506070809101112131415161718192021222377,77)">importos`frommultiprocessingimportProcessdefrun_proc(name):"""定义函数"""print`(`'子进程%s(%s)正在运行。..'%(name,os.getpid()))if__name__=`='__main__'`:#打印当前进程pidprint`(`'父进程%s.'%os.getpid())#生成进程在循环中Exampleforiinrange`(5):`p=Process(target`=run_proc,args=str(i))`print`('Processwillstart.')`p.start()#Pleasepay注意这里的join,默认父进程执行完自己的任务后退出,#此时子进程会继续执行自己的任务,直到自己的任务结束,加上#join后,join完成的工作是进程同步,即父进程任务结束后,#进入阻塞状态,等待其他子进程执行结束,然后主进程终止p.join()print`('Processend.')`结果如下:[Python]纯文本视图__复制代码?010203040506070809101112父进程3488.Processwillstart.Processwillstart.Processwillstart.Processwillstart.Processwillstart.childprocess0(`3148`)running...childprocess3(`12580`)正在运行...子进程ess2(`2668`)正在运行...子进程1(`13664`)正在运行...子进程4(`13916`)正在运行...进程结束。以上两种方式都可以生成少量的进程,但是如果生成了上百个进程就不是那么容易实现了,这时候进程池Pool就派上用场了Poolmultiprocessing提供了一个Pool类来表示进程池对象。Pool可以提供指定数量的进程供用户调用。默认大小是cpu核心数。如果一个新的请求被提交到Pool,如果进程池没有满,它会创建一个Createanewprocess来执行这个请求。如果进程池已满,请求将等待进程池中的一个进程结束,然后再创建新进程。参见示例:[Python]纯文本视图字体样式`="color:rgb(77,77,77)">importos`importtimeimportrandomfrommultiprocessingimportPooldefrun_task(name):print`(`'Tast%s(%s)isrunning'%(name,os.getpid()))#waitingtimetime.sleep(random.random()*3`)`print`(`'Task%send.'%name)if__name__=`='__main__'`:print`(`'当前进程%s.'%os.getpid())#创建一个进程池p,容量为3=Pool(processes`=3)`#按顺序执行5个进程foriinrange`(5):`#apply_async非阻塞模式p.apply_async(run_task,args`=str(i))`print`('为所有子进程写完。..')`#调用close后不能再添加新进程p.close()#调用join方法会等待所有子进程结束,执行joinp.join()print`('Allsubprocesseddone.')`关闭后的程序执行结果如下:77,77,77)">当前进程18044。正在为所有子进程编写完成...Tast0(`15000`)正在运行Tast1(`16796`)正在运行Tast2(`12500`)正在运行任务0结束。Tast3(`15000`)正在运行任务3结束.Tast4(`15000`)正在运行任务2结束.任务1结束.任务4结束.所有子处理完成。<`/font>进程间通信如果创建了大量的进程,那么进程间通信是必不可少的,Python提供了多种进程间通信方式,我们主要说一下Queue和Pipe,Pipe常用于两个进程之间.通信,Queue用于多个进程之间的通信Queue有两个方法put和get来执行Queue操作:put方法用于向队列中插入数据,get方法用于读取和删除队列的内容。下面举例说明:[Python]纯文本view__复制代码?01020304050607080910111213141516171819202122232425262728293031323334353637383940执行结果如下:[Python]纯文本视图__复制代码?010203040506070809101112131415进程13088正在写入...将url1放入队列...进程7700正在写入...将url4放入队列...进程11688正在读取...从队列中获取url1。从队列中获取url4。将url5放入队列...从队列中获取url5。将url2放入队列中...从队列中获取url2。将url6放入队列中...从队列中获取url6。将url3放入队列中...获取url3fromqueue.<`/font>可以看到上面的例子,两个进程写入数据,一个进程读出数据最后介绍一下Pipe通信。管道通常用于两个进程之间的通信。这两个过程位于管道的两端。返回的conn1和conn2代表管道的两端。注意双工参数。如果为True,则表示全双工模式。发送和接收都可用。如果为False,则表示conn1只负责接收,conn2只负责发送。示例如下:[Python]纯文本视图__复制代码?)">importos`importtimeimportrandomimportmultiprocessing'''更多Python学习资料和源码教程资料可在821460695群免费获取'''defproc_send(pipe,urls):"""Senderfunction"""forurlinurls:print`(`'Process%ssend:%s'%(os.getpid(),url))pipe.send(url)time.sleep(random.random())defproc_recv(pipe):"""接收函数"""whileTrue`:`print`(`'Process%srev:%s'%(os.getpid(),pipe.recv()))time.sleep(random.random())if__name__=`='__main__'`:#创建一个实例pipe=multiprocessing.Pipe()#创建一个发送进程p1=multiprocessing.Process(target`=proc_send,args=(pipe[0],['url_'+str(i)``for``i``in``range(10)]))`#建立接收进程p2=multiprocessing.Process(target`=proc_recv,args=(pipe[1`],))#启动p1.start()p2.start()#等待执行完成p1.join()p2.join()<`/font>还创建了两个子进程,一个发送数据,一个接收数据,结果为如下:[Python]纯文本View__复制代码?0102030405060708091011121314151617181920Process16904send:url_0Process2016rev:url_0Processend1016:url_1Process16904send:url_2Process2016rev:url_2Process16904send:url_3Process2016rev:url_3Process16904send:url_4Process16904send:url_5Process2016rev:url_4Process16904send:url_6Process2016rev:url_5Process2016rev:url_6Process16904send:url_7Process2016rev:url_7Process16904发送:url_8Process2016版本:url_8Process16904发送:url_9Process2016版本:url_9<`/font>