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)