集中式与分布式:
集中式:是指数据库中的数据集中存储在一台计算机上,数据的处理集中在一台计算机上完成。
分布式:是指数据存放在计算机网络不同场地的计算机中,每一场地都有能力并完成局部应用,而每一场地也参与(至少一种)全局应用程序的执行,全局应用程序可通过网络通信访问系统中的多个场地的数据
系统中的水平垂直扩展:
垂直:意指系统的硬件设备跟软件,就目前的形式已经发展到一定的水平了,想要扩展,无非是加内存,优化代码,但也是有限的
水平扩展:既然一台计算机上无法实现,那么就多整几个(可以多次分发),利用网络通信连接到一个主机上
一、JoinableQueue模块:
#JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
#参数介绍:
maxsize是队列中允许最大项数,省略则无大小限制。
#方法介绍:
JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
from multiprocessing import JoinableQueue,Process import time,random def producer(food,name,q): # 生产者 for i in range(2): time.sleep(random.randint(1,3)) res='%s%s' %(food,i) q.put(res) print('厨师 %s 生产了 %s' %(name,res)) q.join() def consumer(name,q): # 消费者 while True: res=q.get() if res is None:break time.sleep(random.randint(1,3)) print('%s 吃了 %s' %(name,res)) q.task_done() # 向q.join()发送一次信号,证明一个数据已经被取走了 if __name__ == '__main__': q=JoinableQueue() p1=Process(target=producer,args=('泔水','egon',q)) p2=Process(target=producer,args=('骨头','aaa',q)) p3=Process(target=producer,args=('包子','bbb',q)) c1=Process(target=consumer,args=('alex',q)) c2=Process(target=consumer,args=('haha',q)) c1.daemon = True c2.daemon = True p_l=[p1,p2,p3,c1,c2] for p in p_l: p.start() p1.join() p2.join() p3.join() print('主') #主进程等--->p1,p2,p3等---->c1,c2 #p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据 #因而c1,c2也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程
二、Manager:共享内存空间
进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的
虽然进程间数据独立,但可以通过Manager实现数据共享
from multiprocessing import Manager,Process,Lock def work(d,lock): with lock: # temp=d['count'] d['count']-=1 if __name__ == '__main__': n=Manager() # 实例化产生一个manager对象 d=n.dict({"count":100}) # 对象产生一个字典(可以是任何数据) lock=Lock() p_l=[] for i in range(100): # 开启的进程数 p=Process(target=work,args=(d,lock)) p_l.append(p) p.start() for p in p_l: p.join() # 父进程必须等到子进程执行完成后才能执行下一步 print(d)
三、进程池
Pool:创建进程池和控制进程的数目,默认的个数是根据CPU的核数
进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止
from multiprocessing import Pool import os,time,random def work(n): print('%s is working' %os.getpid()) time.sleep(random.randint(1,3)) return n**2 if __name__ == '__main__': p=Pool(2) objs=[] for i in range(5): # 同步调用:提交完任务后,在原地等待任务结束,一旦结束可以立刻拿到结果 res=p.apply(work,args=(i,)) print(res) # 异步调用:提交完任务后,不会在原地等待任务结束,会继续提交下一次任务,等到所有任务都结束后,才get结果 obj=p.apply_async(work,args=(i,)) objs.append(obj) p.close() # 等子进程执行完毕后关闭进程池 p.terminate() # 立刻关闭进程池 p.join() # 没有join会立即结束 for obj in objs: print(obj.get()) print("主") # 阻塞:正在运行的进程遇到io则进入阻塞状态 # 非阻塞:可能是运行状态,也可能是就绪状态
进程池中有以下几个主要方法:
- apply:从进程池里取一个进程并执行
- apply_async:apply的异步版本
- terminate:立刻关闭线程池
- join:主进程等待所有子进程执行完毕,必须在close或terminate之后
- close:等待所有进程结束后,才关闭线程池
四、回调函数
什么是回调函数:通过一个函数内存调用的函数,如果将这个函数的地址当作参数传给另一个函数,当这个函数的地址用来调用其所只想的函数是,这个所指向的函数就是回调函数
callback:后面加上的是回调函数
回调函数的进程其实就是主进程。
用回调函数实现一个网络爬虫;需要用到requests模块
get:获取网址
status_code:返回状态码
text:查看下载网址的内容
from multiprocessing import Pool,Process import requests,os,time,random def get(url): print('%s GET %s'%(os.getpid(),url)) response=requests.get(url) time.sleep(random.randint(1,3)) if response.status_code==200: return {'url':url,'text':response.text} def parse(dic): print('%s PARSE %s'%(os.getpid(),dic['url'])) time.sleep(1) res='%s:%s\n' %(dic['url'],len(dic['text'])) with open('db.txt','a') as f: f.write(res) if __name__ == '__main__': urls=[ 'https://www.baidu.com', 'https://www.python.org', 'https://www.openstack.org', 'https://help.github.com/', 'http://www.sina.com.cn/' ] p=Pool() start_time=time.time() objs=[] for url in urls: obj=p.apply_async(get,args=(url,),callback=parse) #主进程负责干回调函数的活 objs.append(obj) p.close() p.join() print('主',(time.time()-start_time))
多进程友情链接:http://www.cnblogs.com/linhaifeng/articles/7428874.html