分布式进程:分布式进程是指将Process分布到多台机器上,充分利用多台机器的性能来完成复杂任务的过程。在Thread和Process中,Process应该是首选,因为Process更稳定,而且Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。Python的multiprocessing模块不仅支持多进程,managers子模块也支持将多个进程分布到多台机器上。服务进程可以充当调度程序,依靠网络通信将任务分发给其他进程。由于managers模块被很好的封装,在不知道网络通信细节的情况下,很容易编写分布式多进程程序。比如:在做爬虫程序的时候,我们经常会遇到这样的场景。我们要抓取图片的链接地址,将链接地址存入Queue中,另外一个进程负责从Queue中读取链接地址下载并存入本地。现在让这个过程分布式。一台机器上的进程负责抓取链接,其他机器上的进程负责下载和存储。那么遇到的主要问题就是将Queue暴露在网络中,让其他机器进程可以访问,分布式进程封装了这个过程,我们可以把这个过程称为队列的联网。创建分布式进程需要服务进程和任务进程:服务进程创建:创建队列Queue,用于进程间通信。服务进程创建一个任务队列task_queue,作为向任务进程传递任务的通道;服务进程创建一个结果队列result_queue,作为任务进程完成任务后回复服务进程的通道。在分布式多进程环境下,必须通过Queuemanager获取Queue接口来添加任务。将第一步建立的队列注册到网络上,暴露给其他进程(主机)。注册后得到网络队列,相当于queue队列的形象。创建一个hazard(Quueuemanager(BaseManager))实例管理器,绑定端口并验证密码。启动第三步创建的实例,即启动管理管理器,通过管理实例的方法监听信息通道获取通过网络访问的Queue对象,即将网络队列物化为本地可以使用的队列。创建任务到“本地”队列中,任务自动上传到网络队列,分配给任务进程处理。注意:我这里是基于window操作系统的,和linux系统会有所不同编码:utf-8taskManager.pyforwin>importQueue>frommultiprocessing.managersimportBaseManager>frommultiprocessingimportfreeze_support任务号task_num=10定义了发送和接收队列task_queue=Queue.Queue(task_num)result_queue=Queue.Queue(task_num)defget_task():returntask_queuedefget_result():returnresult_queue创建类似QueueManager类QueueManager(BaseManager):passdefwin_run():#bindwindowsLambda下的call接口无法使用,只能先定义函数再bind认证密码,windowsIP地址下需要填写,linux下不用填写,默认是localmanager=QueueManager(address=('127.0.0.1',4000),authkey='qty')#start经理。start()#通过网络获取任务队列和结果队列task=manager.get_task_queue()result=manager.get_result_queue()try:#Addtaskforiinrange(10):print'puttask%s...'%itask.put(i)print'尝试获取结果。..'foriinrange(10):print'resultis%s'%result.get(timeout=10)except:print'manageerror'finally:#必须关闭,否则会报管理未关闭的错误manager.shutdown()print'masterexit!'ifname=='__main__':#windows下多进程可能有问题。添加这句话可以缓解freeze_support()win_run()任务过程使用QueueManager注册获取Queue的方法名。任务进程只能使用名称在网络中注册获取连接服务器上的Queue,保持端口和验证密码与服务进程中完全一致从网络中获取Queue,执行本地化从Task队列中获取任务,并把结果队列编码:utf-8importtimefrommultiprocessing.managersimportBaseManager创建一个类似的QueueManager:classQueueManager(BaseManager):pass第一步:使用QueueManager注册获取Queue的方法名QueueManager.register('get_task_queue')QueueManager.register('get_result_queue')第二步:连接服务器server_addr='127.0.0.1'print"连接服务器%s"%server_addr端口和验证密码注意和服务进程完全一样m=QueueManager(address=(server_addr,4000),authkey='qty')connectfromthenetworkm.connect()第三步:获取Queue对象task=m.get_task_queue()result=m.get_result_queue()第四步:获取任务来自任务队列并将结果写入结果队列:whilenottask.empty():index=task.get(True,timeout=10)print'runtaskdownload%s'%str(index)result.put('%s---->success'%str(index))处理结束打印'workerexit.'执行结果先运行:服务进程获取结果puttask0...puttask1...puttask2...puttask3...puttask4...puttask5...puttask6...puttask7...puttask8...puttask9....trygetresult...然后立即运行:task进程获取结果,防止获取不到结果进程结束,必须立即执行连接服务器127.0.0.1运行任务下载0运行任务下载1运行任务下载2运行任务下载3运行任务下载4运行任务下载5运行任务下载6运行任务下载7运行任务下载8运行任务下载9worker退出。最后回头看看服务进程窗口的结果puttask0...puttask1...puttask2...puttask3...puttask4...puttask5...puttask6...放置任务7...放置任务8...放置任务9...尝试获取结果...结果为0-->成功结果为1---->成功结果为2---->成功结果为3---->成功结果为4---->成功结果为5---->成功结果为6---->成功结果为7---->成功结果is8---->successresultis9---->successmasterexit!这是一个简单的但是对于真正的分布式计算,稍微修改一下代码,启动多个worker,将任务分发到几台甚至几十台机器上,就可以实现大规模的分布式爬虫
