多进程三

集中式与分布式:

  集中式:是指数据库中的数据集中存储在一台计算机上,数据的处理集中在一台计算机上完成。

  分布式:是指数据存放在计算机网络不同场地的计算机中,每一场地都有能力并完成局部应用,而每一场地也参与(至少一种)全局应用程序的执行,全局应用程序可通过网络通信访问系统中的多个场地的数据

系统中的水平垂直扩展:

  垂直:意指系统的硬件设备跟软件,就目前的形式已经发展到一定的水平了,想要扩展,无非是加内存,优化代码,但也是有限的

  水平扩展:既然一台计算机上无法实现,那么就多整几个(可以多次分发),利用网络通信连接到一个主机上

一、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也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程
View Code

   二、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则进入阻塞状态
# 非阻塞:可能是运行状态,也可能是就绪状态

进程池中有以下几个主要方法:

  1. apply:从进程池里取一个进程并执行
  2. apply_async:apply的异步版本
  3. terminate:立刻关闭线程池
  4. join:主进程等待所有子进程执行完毕,必须在close或terminate之后
  5. 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



转载于:https://www.cnblogs.com/sunxiansheng/p/7657776.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值