【溯源码燕窝密盏】【import源码解析】【libedit源码编译】乐购源码二开_乐购源码二开版本
1.python进程数多少合适
python进程数多少合适
导读:很多朋友问到关于python进程数多少合适的乐购相关问题,本文首席CTO笔记就来为大家做个详细解答,源码供大家参考,开乐希望对大家有所帮助!购源一起来看看吧!码开pythonmultiprocessing最大多少进程最大进程只受操作系统资源限制.
不是版本溯源码燕窝密盏进程越多越好,程序的速度就越快.
一般有几个CPU核心,就开多少进程,或者核心数的N倍.
python多进程
基于官方文档:
日乐购,刚才看到的乐购一个博客,写的源码都不太对,还是开乐基于官方的比较稳妥
我就是喜欢抄官方的,哈哈
通常我们使用Process实例化一个进程,购源并调用他的码开start()方法启动它。
这种方法和Thread是版本一样的。
上图中,乐购我写了p.join()所以主进程是源码等待子进程执行完后,才执行print("运行结束")
否则就是开乐反过来了(这个不一定,看你的语句了,顺序其实是随机的)例如:
主进加个sleep
所以不加join(),其实子进程和主进程是各干各的,谁也不等谁。都执行完后,文件运行就结束了
上面我们用了os.getpid()和os.getppid()获取当前进程,和父进程的id
下面就讲一下,这两个函数的用法:
os.getpid()
返回当前进程的id
os.getppid()
返回父进程的id。父进程退出后,unix返回初始化进程(1)中的import源码解析一个
windows返回相同的id(可能被其他进程使用了)
这也就解释了,为啥我上面的程序运行多次,第一次打印的parentid都是了。
而子进程的父级processid是调用他的那个进程的id:
视频笔记:
多进程:使用大致方法:
参考:进程通信(pipe和queue)
pool.map(函数可以有return也可以共享内存或queue)结果直接是个列表
poll.apply_async()(同map,只不过是一个进程,返回结果用xx.get()获得)
报错:
参考:
把pool=Pool()放到ifname=="main":下面初始化搞定。
结果:
这个肯定有解释的
测试多进程计算效果:
进程池运行:
结果:
普通计算:
我们同样传入三个参数测试:
其实对比下来开始快了一半的;
我们把循环里的数字去掉一个0;
单进程:
多进程:
两次测试单进程/进程池分别为0.和0.几乎成正比的。
问题二:
视图:
post视图里面
Music类:
直接报错:
写在类里面也在函数里用self.pool调用也不行,也是相同的错误。
最后把pool=Pool直接写在search函数里面,奇迹出现了:
前台也能显示搜索的音乐结果了
总结一点,进程这个东西,最好写在直接运行的函数里面,而不是一个函数跳来跳去。因为最后可能是在子进程的子进程运行的,这是不许的,会报错。
还有一点,多进程运行的函数对象,不能是lambda函数。也许lambda虚拟,在内存
使用pool.map子进程函数报错,导致整个pool挂了:
参考:
主要你要,对函数内部捕获错误,而不能让异常抛出就可以了。libedit源码编译
关于map传多个函数参数
我一开始,就是正常思维,多个参数,搞个元祖,让参数一一对应不就行了:
报错:
参考:
普通的process当让可以穿多个参数,map却不知道咋传的。
apply_async和map一样,不知道咋传的。
最简单的方法:
使用starmap而不是map
结果:
子进程结束
1.
成功拿到结果了
关于map和starmap不同的地方看源码:
关于apply_async(),我没找到多参数的方法,大不了用一个迭代的starmap实现。哈哈
关于上面源码里面有itertools.starmap
itertools用法参考:
有个问题,多进程最好不要使用全部的cpu,因为这样可能影响其他任务,所以在进程池添加process参数指定,cpu个数:
上面就是预留了一个cpu干其他事的
后面直接使用Queue遇到这个问题:
解决:
Manager().Queue()代替Queue()
因为queue.get()是堵塞型的,所以可以提前判断是不是空的,以免堵塞进程。比如下面这样:
使用queue.empty()空为True
python并发编程-进程池在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。多进程是实现并发的手段之一,需要注意的问题是:
例如当被操作对象数目不大时,可以直接利用multiprocessing中的udhcpc源码解析Process动态成生多个进程,十几个还好,但如果是上百个,上千个。。。手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
我们就可以通过维护一个进程池来控制进程数目,比如httpd的进程模式,规定最小进程数和最大进程数..
ps:对于远程过程调用的高级应用程序而言,应该使用进程池,Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,就重用进程池中的进程。
创建进程池的类:如果指定numprocess为3,则进程池会从无到有创建三个进程,然后自始至终使用这三个进程去执行所有任务,不会开启其他进程
参数介绍:
方法介绍:
主要方法:
其他方法(了解部分)
应用:
发现:并发开启多个客户端,族谱App源码服务端同一时间只有3个不同的pid,干掉一个客户端,另外一个客户端才会进来,被3个进程之一处理
回调函数:
需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数
我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。
如果在主进程中等待进程池中所有任务都执行完毕后,再统一处理结果,则无需回调函数
python单个进程最大连接数python单个进程最大连接数默认为为。socket连接数的理论值应该和一个进程所能打开的最大文件描述符数相等。
python多进程为什么一定要前面讲了为什么Python里推荐用多进程而不是多线程,但是多进程也有其自己的限制:相比线程更加笨重、切换耗时更长,并且在python的多进程下,进程数量不推荐超过CPU核心数(一个进程只有一个GIL,所以一个进程只能跑满一个CPU),因为一个进程占用一个CPU时能充分利用机器的性能,但是进程多了就会出现频繁的进程切换,反而得不偿失。
不过特殊情况(特指IO密集型任务)下,多线程是比多进程好用的。
举个例子:给你W条url,需要你把每个url对应的页面抓取保存起来,这种时候,单单使用多进程,效果肯定是很差的。为什么呢看
例如每次请求的等待时间是2秒,那么如下(忽略cpu计算时间):
1、单进程+单线程:需要2秒*W=W秒==.个小时==.3天,这个速度明显是不能接受的2、单进程+多线程:例如我们在这个进程中开了个多线程,比1中能够提升倍速度,也就是大约4.天能够完成W条抓取,请注意,这里的实际执行是:线程1遇见了阻塞,CPU切换到线程2去执行,遇见阻塞又切换到线程3等等,个线程都阻塞后,这个进程就阻塞了,而直到某个线程阻塞完成后,这个进程才能继续执行,所以速度上提升大约能到倍(这里忽略了线程切换带来的开销,实际上的提升应该是不能达到倍的),但是需要考虑的是线程的切换也是有开销的,所以不能无限的启动多线程(开W个线程肯定是不靠谱的)3、多进程+多线程:这里就厉害了,一般来说也有很多人用这个方法,多进程下,每个进程都能占一个cpu,而多线程从一定程度上绕过了阻塞的等待,所以比单进程下的多线程又更好使了,例如我们开个进程,每个进程里开W个线程,执行的速度理论上是比单进程开W个线程快倍以上的(为什么是倍以上而不是倍,主要是cpu切换W个线程的消耗肯定比切换W个进程大得多,考虑到这部分开销,所以是倍以上)。
还有更好的方法吗看答案是肯定的,它就是:
4、协程,使用它之前我们先讲讲what/why/how(它是什么/为什么用它/怎么使用它)what:
协程是一种用户级的轻量级线程。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:
协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。
在并发编程中,协程与线程类似,每个协程表示一个执行单元,有自己的本地数据,与其它协程共享全局数据和其它资源。
why:
目前主流语言基本上都选择了多线程作为并发设施,与线程相关的概念是抢占式多任务(Preemptivemultitasking),而与协程相关的是协作式多任务。
不管是进程还是线程,每次阻塞、切换都需要陷入系统调用(systemcall),先让CPU跑操作系统的调度程序,然后再由调度程序决定该跑哪一个进程(线程)。
而且由于抢占式调度执行顺序无法确定的特点,使用线程时需要非常小心地处理同步问题,而协程完全不存在这个问题(事件驱动和异步程序也有同样的优点)。
因为协程是用户自己来编写调度逻辑的,对CPU来说,协程其实是单线程,所以CPU不用去考虑怎么调度、切换上下文,这就省去了CPU的切换开销,所以协程在一定程度上又好于多线程。
how:
python里面怎么使用协程看答案是使用gevent,使用方法:看这里使用协程,可以不受线程开销的限制,我尝试过一次把W条url放在单进程的协程里执行,完全没问题。
所以最推荐的方法,是多进程+协程(可以看作是每个进程里都是单线程,而这个单线程是协程化的)多进程+协程下,避开了CPU切换的开销,又能把多个CPU充分利用起来,这种方式对于数据量较大的爬虫还有文件读写之类的效率提升是巨大的。
小例子:
#-*-coding=utf-8-*-
importrequests
frommultiprocessingimportProcess
importgevent
fromgeventimportmonkey;monkey.patch_all()importsys
reload(sys)
sys.setdefaultencoding('utf8')
deffetch(url):
try:
s=requests.Session()
r=s.get(url,timeout=1)#在这里抓取页面
exceptException,e:
printe
return''
defprocess_start(tasks):
gevent.joinall(tasks)#使用协程来执行
deftask_start(filepath,flag=):#每W条url启动一个进程withopen(filepath,'r')asreader:#从给定的文件中读取urlurl=reader.readline().strip()
task_list=[]#这个list用于存放协程任务
i=0#计数器,记录添加了多少个url到协程队列whileurl!='':
i+=1
task_list.append(gevent.spawn(fetch,url,queue))#每次读取出url,将任务添加到协程队列ifi==flag:#一定数量的url就启动一个进程并执行p=Process(target=process_start,args=(task_list,))p.start()
task_list=[]#重置协程队列
i=0#重置计数器
url=reader.readline().strip()
iftask_listnot[]:#若退出循环后任务队列里还有url剩余p=Process(target=process_start,args=(task_list,))#把剩余的url全都放到最后这个进程来执行p.start()
if__name__=='__main__':
task_start('./testData.txt')#读取指定文件细心的同学会发现:上面的例子中隐藏了一个问题:进程的数量会随着url数量的增加而不断增加,我们在这里不使用进程池multiprocessing.Pool来控制进程数量的原因是multiprocessing.Pool和gevent有冲突不能同时使用,但是有兴趣的同学可以研究一下gevent.pool这个协程池。
另外还有一个问题:每个进程处理的url是累积的而不是独立的,例如第一个进程会处理W个,第二个进程会变成W个,以此类推。最后定位到问题是gevent.joinall()导致的问题,有兴趣的同学可以研究一下为什么会这样。不过这个问题的处理方案是:主进程只负责读取url然后写入到list中,在创建子进程的时候直接把list传给子进程,由子进程自己去构建协程。这样就不会出现累加的问题
python进程池最大数量初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
结语:以上就是首席CTO笔记为大家介绍的关于python进程数多少合适的全部内容了,希望对大家有所帮助,如果你还想了解更多这方面的信息,记得收藏关注本站。