day 34 共享数据,初识进程池,进程池中的其他方法,进程池中的回调函数,线程的概念...

共享数据---了解

from multiprocessing import Manager

 

数据共享:速度很慢,牵扯到锁的问题            可以使用数据库来解决数据共享的问题

进程间数据是独立的,可以借助于队列或管道实现通信,二者都是基于消息传递的
虽然进程间数据独立,但可以通过Manager实现数据共享,事实上Manager的功能远不止于此

A manager object returned by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.

A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array.

Manager模块介绍

 

内部管理了很多数据类型
并不是所有的数据类型都是用来做数据共享
只是顺便包含了能够处理数据共享问题的数据类型



from multiprocessing import Manager,Process,Lock

def func(dic,lock):
    with lock:
        dic['count'] -= 1

if __name__ == '__main__':
    m = Manager()
    lock = Lock()
    dic = m.dict({'count':100})
    p_l = []
    for i in range(100):
        p = Process(target=func,args=(dic,lock))
        p.start()
        p_l.append(p)
    for p in p_l:p.join()
    print(dic)

 

 

进程池

进程池内每个进程的pid是不同的

异步提交

异步提交就是不可靠概念,不依赖于单个进程是否执行完毕,效率很高

多个进程可以利用多核cpu(进程池)

异步提交概念:多个进程利用多核cpu,如果可以忽略IO操作,这个时候我们启超过cpu个数过多的进程个数反而会降低程序的执行效率,反之会大大提高效率,进程池是用来处理多进程,并且有IO的时候发挥最大效率

未来我们用多进程解决的都是高计算型场景(忽略IO)

import os
import time
import random
from multiprocessing import Pool,Process

def func(i,):
    time.sleep(random.uniform(2,4))  #这里用sleep是为了模仿真实生产环境中执行任务时的延迟,这样就会让进程池内的四个进程都执行任务,如果没有延迟单个进程就会把任务执行完毕.
    print(i,os.getpid())  #这里了模仿提交一个任务,获取pid

if __name__ == '__main__':
    p = Pool()   #默认是根据cpu的个数来创建进程池的数量
    for i in range(20):
        p.apply_async(func,(i,))   #apply是提交任务,  async是异步 这里已经把任务提交到进程池内,在执行了
    p.close()  #必须告诉进程什么时候关闭,否则会随着我们进程的借宿而结束,关闭进程池,不允许再向这个池子中添加任务了
    p.join()  #阻塞,直到已经被提交到进程池的任务全部结束,执行完p.close和p.join之后就可以打印出执行任务的数据了

#结果   我们可以看到有四个不同的pid,说明四个进程都执行了任务
3 107496
1 62496
2 38884
0 20668
6 38884
7 20668
5 62496
4 107496
8 38884
9 20668
10 62496
11 107496
13 20668
12 38884
14 62496
15 107496
17 38884
16 20668
18 62496
19 107496

 

异步提交获取结果
###########方法1############
import time
import random
from multiprocessing import Pool


def func(i):
    i * i
    time.sleep(2)
    return "i" * i


if __name__ == '__main__':
    p = Pool(4)     #开启4个进程池
    lst = []
    for i in range(20):
        ret = p.apply_async(func,(i,))
        lst.append(ret)
    # p.close()
    # p.join()     加上close和join是等待任务执行完毕,一下获取列表内所有的结果.生产上为了公平起见一般不加,会让谁先进来取谁的结果.
    for i in lst:
        print(i.get())



#############方法2(map)#################
import time
import random
from multiprocessing import Pool

def func(i):
    i * i
    time.sleep(2)
    return "i" * i

if __name__ == '__main__':
    p = Pool()  #开启进程池
    ret = p.map(func,range(50))     #map就是一种简便的app_async方式,并且内置了close和join的功能
    for i in ret:
        print(i)

 

 

 

同步提交

同步提交程序是串行的,几乎不用.

import os
import time
import random
from multiprocessing import Pool

def func(i):
    time.sleep(random.random())
    print(i,os.getpid())

if __name__ == '__main__':
    p = Pool()
    for i in range(20):
        p.apply(func,(i,))
 回调函数

回调函数是由主进程来执行的

 回调函数版

import os
from urllib import request
from multiprocessing import Pool

def chuli_page(content):
    print("进程池:",os.getpid())   #检验回调函数是主进程执行的还是进程池内的进程执行的
    print(len(content))

def get_url(url):
    ret = request.urlopen(url)
    contont = ret.read().decode("utf-8")
    return contont

if __name__ == '__main__':
    print("主进程:",os.getpid())   ##检验回调函数是主进程执行的还是进程池内的进程执行的,结果为主进程执行的
    url_lst = [
        'http://www.cnblogs.com/Eva-J/articles/8253549.html',
        'http://www.cnblogs.com/Eva-J/articles/8306047.html',
        'http://www.baidu.com',
        'http://www.sogou.com',
        'https://www.cnblogs.com/Eva-J/p/7277026.html'
    ]
    p = Pool()
    for url in url_lst:
        p.apply_async(get_url,(url,),callback=chuli_page)
    p.close()
    p.join()  #不加上close 和 join 进程池没有结束,就不会有输出结果

 

 

普通版

import os
from urllib import request
from multiprocessing import Pool
def chuli_page(content):
    print("进程池:",os.getpid())   #检验回调函数是主进程执行的还是进程池内的进程执行的
    print(len(content))

def get_url(url):
    ret = request.urlopen(url)
    contont = ret.read().decode("utf-8")
    return contont

if __name__ == '__main__':
    print("主进程:",os.getpid())   ##检验回调函数是主进程执行的还是进程池内的进程执行的,结果为主进程执行的
    url_lst = [
        'http://www.cnblogs.com/Eva-J/articles/8253549.html',  # 1
        'http://www.cnblogs.com/Eva-J/articles/8306047.html',  # 0.05
        'http://www.baidu.com',
        'http://www.sogou.com',
        'https://www.cnblogs.com/Eva-J/p/7277026.html'
    ]
    p = Pool()
    ret_l = []
    for url in url_lst:
        ret = p.apply_async(get_url,(url,))
        ret_l.append(ret)
    for ret in ret_l:
        resout = ret.get()
        chuli_page(resout)

 

 

转载于:https://www.cnblogs.com/yanpeizhang/p/10452948.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值