Ⅰ python并发编程之多进程方式(multiprocessing模块)
Python的并发编程提供了多进程方式来提高效率,通过multiprocessing模块实现。下面将详细阐述进程与线程的区别,以及如何使用多进程来优化任务执行。
在并发编程中,进程就像工厂的车间,每个车间运行一个独立的线程,即工人。为了提升生产效率,我们需要理解进程和线程的协作与独立性。
首先,我们通过串行执行程序,将两个数值传递给func函数,逐个处理。这展示了单进程的工作方式,随后引入多进程。Python的multiprocessing模块允许我们创建多个并行运行的进程。通过Process类,我们创建子进程,它们独立于主进程,没有执行顺序,如下面的代码所示:
python
import multiprocessing as mp
# 创建子进程
p1 = mp.Process(target=func, args=(数值1,))
p2 = mp.Process(target=func, args=(数值2,))
主进程在子进程启动后继续执行,由于子进程各自独立轮询,主进程完成的时间会早于子进程。当子进程轮询序列相同时,它们会同时完成,如代码中所述:
python
# 使用join方法等待子进程结束
p1.start()
p2.start()
p1.join()
p2.join()
在实际应用中,尤其是需要处理大量数据或任务的场景,我们可以使用循环来创建多个子进程,以进一步提高效率。通过多进程方式,Python为我们提供了一种高效且灵活的并发解决方案。
Ⅱ python最多开多少进程(python多进程)
导读:今天首席CTO笔记来给各位分享关于python最多开多少进程的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
pythonmultiprocessing最大多少进程最大进程只受操作系统资源限制.
不是进程越多越好,程序的速度就越快.
一般有几个CPU核心,就开多少进程,或者核心数的N倍.
python进程池最大数量初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
python最大支持多少线程
python线程太慢了,想并发去用greenlet吧,快,写起来还方便。
如果加锁同步的话,线程多了反而变慢也有可能。
ulimit-s返回线程栈大小,我的默认是8192,用内存大小除以它就得到理论上的线程数吧。
python之多线程进程的概念:以一个整体的形式暴露给操作系统管理,里面包含各种资源的调用。对各种资源管理的集合就可以称为进程。
线程的概念:是操作系统能够进行运算调度的最小单位。本质上就是一串指令的集合。
进程和线程的区别:
1、线程共享内存空间,进程有独立的内存空间。
2、线程启动速度快,进程启动速度慢。注意:二者的运行速度是无法比较的。
3、线程是执行的指令集,进程是资源的集合
4、两个子进程之间数据不共享,完全独立。同一个进程下的线程共享同一份数据。
5、创建新的线程很简单,创建新的进程需要对他的父进程进行一次克隆。
6、一个线程可以操作(控制)同一进程里的其他线程,但是进程只能操作子进程
7、同一个进程的线程可以直接交流,两个进程想要通信,必须通过一个中间代理来实现。
8、对于线程的修改,可能会影响到其他线程的行为。但是对于父进程的修改不会影响到子进程。
第一个程序,使用循环来创建线程,但是这个程序中一共有51个线程,我们创建了50个线程,但是还有一个程序本身的线程,是主线程。这51个线程是并行的。注意:这个程序中是主线程启动了子线程。
相比上个程序,这个程序多了一步计算时间,但是我们观察结果会发现,程序显示的执行时间只有0.007秒,这是因为最后一个print函数它存在于主线程,而整个程序主线程和所有子线程是并行的,那么可想而知,在子线程还没有执行完毕的时候print函数就已经执行了,总的来说,这个时间只是执行了一个线程也就是主线程所用的时间。
接下来这个程序,吸取了上面这个程序的缺点,创建了一个列表,把所有的线程实例都存进去,然后使用一个for循环依次对线程实例调用join方法,这样就可以使得主线程等待所创建的所有子线程执行完毕才能往下走。注意实验结果:和两个线程的结果都是两秒多一点
注意观察实验结果,并没有执行打印taskhasdone,并且程序执行时间极其短。
这是因为在主线程启动子线程前把子线程设置为守护线程。
只要主线程执行完毕,不管子线程是否执行完毕,就结束。但是会等待非守护线程执行完毕
主线程退出,守护线程全部强制退出。皇帝死了,仆人也跟着殉葬
应用的场景:socket-server
注意:gil只是为了减低程序开发复杂度。但是在2.几的版本上,需要加用户态的锁(gil的缺陷)而在3点几的版本上,加锁不加锁都一样。
下面这个程序是一个典型的生产者消费者模型。
生产者消费者模型是经典的在开发架构中使用的模型
运维中的集群就是生产者消费者模型,生活中很多都是
那么,多线程的使用场景是什么?
python中的多线程实质上是对上下文的不断切换,可以说是假的多线程。而我们知道,io操作不占用cpu,计算占用cpu,那么python的多线程适合io操作密集的任务,比如socket-server,那么cpu密集型的任务,python怎么处理?python可以折中的利用计算机的多核:启动八个进程,每个进程有一个线程。这样就可以利用多进程解决多核问题。
python多开是多进程吗python多开是多进程。根据查询相关公开信息显示,多进程类似于多开应用,属于真正的多核任务,各个进程有独立的资源分配,因此跨进程内存共享需要有专用多进程库支持。
python可以多进程吗想要充分利用多核CPU资源,Python中大部分情况下都需要使用多进程,Python中提供了multiprocessing这个包实现多进程。multiprocessing支持子进程、进程间的同步与通信,提供了Process、Queue、Pipe、Lock等组件。
开辟子进程
multiprocessing中提供了Process类来生成进程实例
Process([group[,target[,name[,args[,kwargs]]]]])
group分组,实际上不使用
target表示调用对象,你可以传入方法的名字
args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m,n)即可
kwargs表示调用对象的字典
name是别名,相当于给这个进程取一个名字
先来个小例子:
#-*-coding:utf-8-*-
,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())#获取当前进程号和正在运行是的时间
time.sleep(wTime)#等待(休眠)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))#申请子进程
p.start()#运行进程
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
运行结果:
Parentprocessrun.subProcessis30196
Parentprocessend,MonMar2711:20:212017
subProcess30196run,MonMar2711:20:212017
subProcess30196run,MonMar2711:20:232017
subProcess30196run,MonMar2711:20:252017
根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸(zombie)进程。
通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。
有什么办法可以避免僵尸进程呢?
这里介绍进程的一个属性deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。
所以给上面的程序加上p.deamon=true,看看效果。
#-*-coding:utf-8-*-
,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())
time.sleep(wTime)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))
p.daemon=True#加入daemon
p.start()
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
执行结果:
Parentprocessrun.subProcessis31856
Parentprocessend,MonMar2711:40:102017
这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?
这里引入p.join()方法,它使子进程执行结束后,父进程才执行之后的代码
#-*-coding:utf-8-*-
,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())
time.sleep(wTime)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))
p.daemon=True
p.start()
p.join()#加入join方法
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
执行结果:
subProcess32076run,MonMar2711:46:072017
subProcess32076run,MonMar2711:46:092017
subProcess32076run,MonMar2711:46:112017
Parentprocessrun.subProcessis32076
Parentprocessend,MonMar2711:46:132017
这样所有的进程就能顺利的执行了。
结语:以上就是首席CTO笔记为大家整理的关于python最多开多少进程的相关内容解答汇总了,希望对您有所帮助!如果解决了您的问题欢迎分享给更多关注此问题的朋友喔~
Ⅲ Python中进程multiprocessing用法详解
一、multiprocessing模块
multiprocessing模块提供了一个Process类来代表一个进程对象,multiprocessing模块像线程一样管理进程,这个是multiprocessing的核心,它与threading很相似,对多核CPU的利用率会比threading好的多
看一下Process类的构造方法:
__init__(self,group=None,target=None,name=None,args=(),kwargs={})参数说明:
group:进程所属组(基本不用)
target:表示调用对象
args:表示调用对象的位置参数元组
name:别名
kwargs:表示调用对象的字典
importmultiprocessingdefdo(n):#参数n由args=(1,)传入name=multiprocessing.current_process().name#获取当前进程的名字print(name,'starting')print("worker",n)returnif__name__=='__main__':numList=[]foriinrange(5):p=multiprocessing.Process(target=do,args=(i,))#(i,)中加入","表示元祖numList.append(p)print(numList)p.start()#用start()方法启动进程,执行do()方法p.join()#等待子进程结束以后再继续往下运行,通常用于进程间的同步print("Processend.")运行结果如下:
[<Process(Process-1,initial)>]Process-1startingworker0Processend.[<Process(Process-1,stopped)>,<Process(Process-2,initial)>]Process-2startingworker1Processend.[<Process(Process-1,stopped)>,<Process(Process-2,stopped)>,<Process(Process-3,initial)>]Process-3startingworker2Processend.[<Process(Process-1,stopped)>,<Process(Process-2,stopped)>,<Process(Process-3,stopped)>,<Process(Process-4,initial)>]Process-4startingworker3Processend.[<Process(Process-1,stopped)>,<Process(Process-2,stopped)>,<Process(Process-3,stopped)>,<Process(Process-4,stopped)>,<Process(Process-5,initial)>]Process-5startingworker4Processend.通过打印numList可以看出当前进程结束后,再开始下一个进程
注意:在Windows上要想使用进程模块,就必须把有关进程的代码写在当前.py文件的ifname==>‘main’:语句的下面,才能正常使用Windows下的进程模块。Unix/Linux下则不需要
二、Pool类
Pool类可以提供指定数量的进程供用户调用,当有新的请求提交到Pool中时,如果池还没有满,就会创建一个新的进程来执行请求。如果池满,请求就会告知先等待,直到池中有进程结束,才会创建新的进程来执行这些请求下面介绍一下multiprocessing模块下的Pool类下的几个方法:
1.apply()
函数原型:apply(func[,args=()[,kwds={}]])
该函数用于传递不定参数,同python中的apply函数一致,主进程会被阻塞直到函数执行结束(不建议使用,并且3.x以后不再出现)
2.apply_async
函数原型:apply_async(func[,args=()[,kwds={}[,callback=None]]])
与apply用法一致,但它是非阻塞的且支持结果返回后进行回调
3.map()
函数原型:map(func,iterable[,chunksize=None])
Pool类中的map方法,与内置的map函数用法行为基本一致,它会使进程阻塞直到结果返回注意:虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程
4.map_async()
函数原型:map_async(func,iterable[,chunksize[,callback]])与map用法一致,但是它是非阻塞的
5.close()
关闭进程池(pool),使其不再接受新的任务
6.terminal()
结束工作进程,不再处理未处理的任务
7.join()
主进程阻塞等待子进程的退出,join方法要在close或terminate之后使用
示例1--使用map()函数
(fn):#fn:函数参数是数据列表的一个元素time.sleep(1)print(fn*fn)if__name__=="__main__":testFL=[1,2,3,4,5,6]print('shunxu:')#顺序执行(也就是串行执行,单进程)s=time.time()forfnintestFL:run(fn)t1=time.time()print("顺序执行时间:",int(t1-s))print('concurrent:')#创建多个进程,并行执行pool=Pool(3)#创建拥有3个进程数量的进程池#testFL:要处理的数据列表,run:处理testFL列表中数据的函数pool.map(run,testFL)pool.close()#关闭进程池,不再接受新的进程pool.join()#主进程阻塞等待子进程的退出t2=time.time()print("并行执行时间:",int(t2-t1))1、map函数中testFL为可迭代对象--列表
2、当创建3个进程时,会一次打印出3个结果“1,4,9”,当当创建2个进程时,会一次打印出2个结果“1,4”,以此类推,当创建多余6个进程时,会一次打印出所有结果
3、如果使用Pool(),不传入参数,可以创建一个动态控制大小的进程池
从结果可以看出,并发执行的时间明显比顺序执行要快很多,但是进程是要耗资源的,所以平时工作中,进程数也不能开太大。对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),让其不再接受新的Process了
示例2--使用map()_async函数
print('concurrent:')#创建多个进程,并行执行pool=Pool(3)#创建拥有3个进程数量的进程池#testFL:要处理的数据列表,run:处理testFL列表中数据的函数pool.map_async(run,testFL)pool.close()#关闭进程池,不再接受新的进程pool.join()#主进程阻塞等待子进程的退出t2=time.time()print("并行执行时间:",int(t2-t1))从结果可以看出,map_async()和map()用时相同。目前还没有看出两者的区别,后面知道后再完善
示例3--使用apply()函数
print('concurrent:')#创建多个进程,并行执行pool=Pool(3)#创建拥有3个进程数量的进程池#testFL:要处理的数据列表,run:处理testFL列表中数据的函数forfnintestFL:pool.apply(run,(fn,))pool.close()#关闭进程池,不再接受新的进程pool.join()#主进程阻塞等待子进程的退出t2=time.time()print("并行执行时间:",int(t2-t1))可见,使用apply()方法,并行执行和顺序执行用时相同,经过试验,进程数目增大也不会减少并行执行的时间
原因:以阻塞的形式产生进程任务,生成1个任务进程并等它执行完出池,第2个进程才会进池,主进程一直阻塞等待,每次只执行1个进程任务
示例4--使用apply_async()函数
print('concurrent:')#创建多个进程,并行执行pool=Pool(3)#创建拥有3个进程数量的进程池#testFL:要处理的数据列表,run:处理testFL列表中数据的函数forfnintestFL:pool.apply_async(run,(fn,))pool.close()#关闭进程池,不再接受新的进程pool.join()#主进程阻塞等待子进程的退出t2=time.time()print("并行执行时间:",int(t2-t1))可见,使用apply_async()方法,并行执行时间与使用map()、map_async()方法相同
注意:
map_async()和map()方法,第2个参数可以是列表也可以是元祖,如下图:
而使用apply()和apply_async()方法时,第2个参数只能传入元祖,传入列表进程不会被执行,如下图:
三、apply_async()方法callback参数的用法
示例:注意func2的入参是func1的返回值
_01(i):time.sleep(2)print('start_time:',time.ctime())returni+100deffun_02(arg):print('end_time:',arg,time.ctime())if__name__=='__main__':pool=Pool(3)foriinrange(4):pool.apply_async(func=fun_01,args=(i,),callback=fun_02)#fun_02的入参为fun_01的返回值#pool.apply_async(func=fun_01,args=(i,))pool.close()pool.join()print('done')map_async()方法callback参数的用法与apply_async()相同
四、使用进程池并关注结果
(msg):print('hello:',msg,time.ctime())time.sleep(2)print('end',time.ctime())return'done'+msgif__name__=='__main__':pool=multiprocessing.Pool(2)result=[]foriinrange(3):msg='hello%s'%iresult.append(pool.apply_async(func=func,args=(msg,)))pool.close()pool.join()forresinresult:print('***:',res.get())#get()函数得出每个返回结果的值print('Allend--')五、多进程执行多个函数
使用apply_async()或者apply()方法,可以实现多进程执行多个方法
示例:
():print(' RuntaskLee--%s******ppid:%s'%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(5)end=time.time()print('TaskLee,runs%0.2fseconds.'%(end-start),'~~~~',time.ctime())defMarlon():print(" RuntaskMarlon-%s******ppid:%s"%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(10)end=time.time()print('TaskMarlonruns%0.2fseconds.'%(end-start),'~~~~',time.ctime())defAllen():print(" RuntaskAllen-%s******ppid:%s"%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(15)end=time.time()print('TaskAllenruns%0.2fseconds.'%(end-start),'~~~~',time.ctime())defFrank():print(" RuntaskFrank-%s******ppid:%s"%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(20)end=time.time()print('TaskFrankruns%0.2fseconds.'%(end-start),'~~~~',time.ctime())if__name__=='__main__':func_list=[Lee,Marlon,Allen,Frank]print('parentprocessid%s'%os.getpid())pool=multiprocessing.Pool(4)forfuncinfunc_list:pool.apply_async(func)print('Waitingforallsubprocessesdone...')pool.close()pool.join()print('Allsubprocessesdone.')六、其他
1、获取当前计算机的CPU数量
Ⅳ Python多进程multiprocessing模块介绍
multiprocessing 是一个支持使用与 threading 模块类似的 API 来产生进程的包。 multiprocessing 包同时提供了本地和远程并发操作,通过使用子进程而非线程有效地绕过了 全局解释器锁。 因此,multiprocessing 模块允许程序员充分利用给定机器上的多个处理器。 它在 Unix 和 Windows 上均可运行。
1、multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
2、相关方法
输出结果如下:
Pool提供了一种快捷的方法,赋予函数并行化处理一系列输入值的能力,可以将输入数据分配给不同进程处理(数据并行)。下面的例子演示了在模块中定义此类函数的常见做法,以便子进程可以成功导入该模块。这个数据并行的基本例子使用了 Pool 。
将在标准输出中打印
其中:
(1)p.apply(func [, args [, kwargs]]):在一个池工作进程中执行func( args, kwargs),然后返回结果。需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用p.apply_async()
(2)p.apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func( args,**kwargs),然后返回结果。此方法的结果是 AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。多进程并发!
(3)p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
(4)p.jion():等待所有工作进程退出。此方法只能在close()或teminate()之后调用
Ⅳ python中的进程-实战部分
如果想了解进程 可以先看一下这一篇 python中的进程-理论部分
python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。
multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。
multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。
创建进程的类 :
参数介绍:
group参数未使用,值始终为None
target表示调用对象,即子进程要执行的任务
args表示调用对象的位置参数元组,args=(1,2,'tiga',)
kwargs表示调用对象的字典,kwargs={'name':'tiga','age':18}
name为子进程的名称
方法介绍:
p.start():启动进程,并调用该子进程中的p.run()
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法
p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True
p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
属性介绍:
注意:在windows中Process()必须放到# if __name__ == '__main__':下
创建并开启子进程的两种方式
方法一:
方法二:
有了join,程序不就是串行了吗???
terminate与is_alive
name与pid