python进程管理
‘壹’ python中进程与线程的区别是什么
Num01–>线程
线程是操作系统中能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。
一个线程指的是进程中一个单一顺序的控制流。
一个进程中可以并发多条线程,每条线程并行执行不同的任务。
Num02–>进程
进程就是一个程序在一个数据集上的一次动态执行过程。
进程有以下三部分组成:
1,程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成。
2,数据集:数据集则是程序在执行过程中需要的资源,比如图片、音视频、文件等。
3,进程控制块:进程控制块是用来记录进程的外部特征,描述进程的执行变化过程,系统可以用它来控制和管理进程,它是系统感知进程存在的唯一标记。
Num03–>进程和线程的区别:
1、运行方式不同:
进程不能单独执行,它只是资源的集合。
进程要操作CPU,必须要先创建一个线程。
所有在同一个进程里的线程,是同享同一块进程所占的内存空间。
2,关系
进程中第一个线程是主线程,主线程可以创建其他线程;其他线程也可以创建线程;线程之间是平等的。
进程有父进程和子进程,独立的内存空间,唯一的标识符:pid。
3,速度
启动线程比启动进程快。
运行线程和运行进程速度上是一样的,没有可比性。
线程共享内存空间,进程的内存是独立的。
4,创建
父进程生成子进程,相当于复制一份内存空间,进程之间不能直接访问
创建新线程很简单,创建新进程需要对父进程进行一次复制。
一个线程可以控制和操作同级线程里的其他线程,但是进程只能操作子进程。
5,交互
同一个进程里的线程之间可以直接访问。
两个进程想通信必须通过一个中间代理来实现。
相关推荐:《Python视频教程》
Num04–>几个常见的概念
1,什么的并发和并行?
并发:微观上CPU轮流执行,宏观上用户看到同时执行。因为cpu切换任务非常快。
并行:是指系统真正具有同时处理多个任务(动作)的能力。
2,同步、异步和轮询的区别?
同步任务:B一直等着A,等A完成之后,B再执行任务。(打电话案例)
轮询任务:B没有一直等待A,B过一会来问一下A,过一会问下A
异步任务:B不需要一直等着A, B先做其他事情,等A完成后A通知B。(发短信案例)
Num05–>进程和线程的优缺点比较
首先,要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常是一个Master,多个Worker。
如果用多进程实现Master-Worker,主进程就是Master,其他进程就是Worker。
如果用多线程实现Master-Worker,主线程就是Master,其他线程就是Worker。
多进程模式最大的优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。(当然主进程挂了所有进程就全挂了,但是Master进程只负责分配任务,挂掉的概率低)着名的Apache最早就是采用多进程模式。
多进程模式的缺点是创建进程的代价大,在Unix/linux系统下,用fork调用还行,在Windows下创建进程开销巨大。另外,操作系统能同时运行的进程数也是有限的,在内存和CPU的限制下,如果有几千个进程同时运行,操作系统连调度都会成问题。
多线程模式通常比多进程快一点,但是也快不到哪去,而且,多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。在Windows上,如果一个线程执行的代码出了问题,你经常可以看到这样的提示:“该程序执行了非法操作,即将关闭”,其实往往是某个线程出了问题,但是操作系统会强制结束整个进程。
在Windows下,多线程的效率比多进程要高,所以微软的IIS服务器默认采用多线程模式。由于多线程存在稳定性的问题,IIS的稳定性就不如Apache。为了缓解这个问题,IIS和Apache现在又有多进程+多线程的混合模式,真是把问题越搞越复杂。
Num06–>计算密集型任务和IO密集型任务
是否采用多任务的第二个考虑是任务的类型。我们可以把任务分为计算密集型和IO密集型。
第一种:计算密集型任务的特点是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。
计算密集型任务由于主要消耗CPU资源,因此,代码运行效率至关重要。Python这样的脚本语言运行效率很低,完全不适合计算密集型任务。对于计算密集型任务,最好用C语言编写。
第二种:任务的类型是IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。
IO密集型任务执行期间,99%的时间都花在IO上,花在CPU上的时间很少,因此,用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言,完全无法提升运行效率。对于IO密集型任务,最合适的语言就是开发效率最高(代码量最少)的语言,脚本语言是首选,C语言最差。
相关推荐:
Python中的进程是什么
‘贰’ python 多进程 进程池子进程结束怎么获取
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,10几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,这时候进程池Pool发挥作用的时候就到了。
Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。这里有一个简单的例子:
#!/usr/bin/env python
#coding=utf-8
"""
Author: Squall
Last modified: 2011-10-18 16:50
Filename: pool.py
Description: a simple sample for pool class
"""
from multiprocessing import Pool
from time import sleep
def f(x):
for i in range(10):
print '%s --- %s ' % (i, x)
sleep(1)
def main():
pool = Pool(processes=3) # set the processes max number 3
for i in range(11,20):
result = pool.apply_async(f, (i,))
pool.close()
pool.join()
if result.successful():
print 'successful'
if __name__ == "__main__":
main()
先创建容量为3的进程池,然后将f(i)依次传递给它,运行脚本后利用ps aux | grep pool.py查看进程情况,会发现最多只会有三个进程执行。pool.apply_async()用来向进程池提交目标请求,pool.join()是用来等待进程池中的worker进程执行完毕,防止主进程在worker进程结束前结束。但必pool.join()必须使用在pool.close()或者pool.terminate()之后。其中close()跟terminate()的区别在于close()会等待池中的worker进程执行结束再关闭pool,而terminate()则是直接关闭。result.successful()表示整个调用执行的状态,如果还有worker没有执行完,则会抛出AssertionError异常。
利用multiprocessing下的Pool可以很方便的同时自动处理几百或者上千个并行操作,脚本的复杂性也大大降低。
‘叁’ python 多线程与多进程问题
监控一个信号就起一个线程与进程处理。这样的逻辑是不太合适的。所有的资源都是有限的,如果这样浪费很快会资源管理失控。
常规的做法是起一个线程池,或者是进程池。 使用线程还是进程取决于你处理的信号的类型。如果计算量大,则需要进程池,如果只是设备等待,比如网络数据收发,则线程也勉强够用。
信号过来后处理方法有两种,一种是实时处理,这个没有好办法,可以用“微线程”的办法做,尽量减少处理周期。另外一种是允许少量的延迟。那么通常的做法是用队列。将信号放到线程或者是进程池的消息队列里。然后再由后者分配。
还有一种高效的处理方法,根据信号的值做hash,然后自动分发到不同的CPU或者是服务器。这个就算是大规模并发处理机制。
通常情况下,比如一个WEB服务器,它需要获取一个请求,然后处理响应,可以使用线程模型,或者是进程模型。也是使用典型的池的方法。一个Pool的大于,取决于你的计算 机的计算 能力,内存大小,以及你的并发访问数量。
所要要启用多少个呢?假设你的一个信号的处理周期是1秒,你同时有100个信号进来,那么就需要100个线程或者是进程。
线程数过多,表面上处理能力在增加,不过延迟也在增加,失败率也会增加。
‘肆’ python怎么让进程暂停
如果在linux运行,就跟普通程序一样就行,查找pid,然后使用kill。如果实在windows,ctrl+alt+delete,打开任务管理器,查找进程,然后结束掉就可以了。
‘伍’ python怎么实现一个进程
想要充分利用多核CPU资源,Python中大部分情况下都需要使用多进程,Python中提供了multiprocessing这个包实现多进程。multiprocessing支持子进程、进程间的同步与通信,提供了Process、Queue、Pipe、Lock等组件。
开辟子进程
multiprocessing中提供了Process类来生成进程实例
Process([group [, target [, name [, args [, kwargs]]]]])1
group分组,实际上不使用
target表示调用对象,你可以传入方法的名字
args表示给调用对象以元组的形式提供参数,比如target是函数a,他有两个参数m,n,那么该参数为args=(m, n)即可
kwargs表示调用对象的字典
name是别名,相当于给这个进程取一个名字
- # -*- coding:utf-8 -*-from multiprocessing import Process, Poolimport osimport timedef run_proc(wTime):
- n = 0
- while n < 3: print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime()) #获取当前进程号和正在运行是的时间
- time.sleep(wTime) #等待(休眠)
- n += 1if __name__ == "__main__":
- p = Process(target=run_proc, args=(2,)) #申请子进程
- p.start() #运行进程
- print "Parent process run. subProcess is ", p.pid print "Parent process end,{0}".format(time.ctime())12345678910111213141516171819
- # -*- coding:utf-8 -*-from multiprocessing import Process, Poolimport osimport timedef run_proc(wTime):
- n = 0
- while n < 3: print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
- time.sleep(wTime)
- n += 1if __name__ == "__main__":
- p = Process(target=run_proc, args=(2,))
- p.daemon = True #加入daemon
- p.start() print "Parent process run. subProcess is ", p.pid print "Parent process end,{0}".format(time.ctime())
- # -*- coding:utf-8 -*-from multiprocessing import Process, Poolimport osimport timedef run_proc(wTime):
- n = 0
- while n < 3: print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
- time.sleep(wTime)
- n += 1if __name__ == "__main__":
- p = Process(target=run_proc, args=(2,))
- p.daemon = True
- p.start()
- p.join() #加入join方法
- print "Parent process run. subProcess is ", p.pid print "Parent process end,{0}".format(time.ctime())21
- # -*- coding:utf-8 -*-from multiprocessing import Process, Poolimport osimport timeclass Myprocess(Process):
- def __init__(self, wTime):
- Process.__init__(self)
- self.wTime = wTime def run(self):
- n = 0
- while n < 3: print "subProcess %s run," % os.getpid(), "{0}".format(time.ctime())
- time.sleep(self.wTime)
- n += 1if __name__ == "__main__":
- p = Myprocess(2)
- p.daemon = True
- p.start() #自动调用run方法
- p.join() print "Parent process run. subProcess is ", p.pid print "Parent process end,{0}".format(time.ctime())2122232425262728
- # -*- coding:utf-8 -*-from multiprocessing import Process,Poolimport os,timedef run_proc(name): ##定义一个函数用于进程调用
- for i in range(5):
- time.sleep(0.2) #休眠0.2秒
- print 'Run child process %s (%s)' % (name, os.getpid())#执行一次该函数共需1秒的时间if __name__ =='__main__': #执行主进程
- print 'Run the main process (%s).' % (os.getpid())
- mainStart = time.time() #记录主进程开始的时间
- p = Pool(8) #开辟进程池
- for i in range(16): #开辟14个进程
- p.apply_async(run_proc,args=('Process'+str(i),))#每个进程都调用run_proc函数,
- #args表示给该函数传递的参数。
- print 'Waiting for all subprocesses done ...'
- p.close() #关闭进程池
- p.join() #等待开辟的所有进程执行完后,主进程才继续往下执行
- print 'All subprocesses done'
- mainEnd = time.time() #记录主进程结束时间
- print 'All process ran %0.2f seconds.' % (mainEnd-mainStart) #主进程执行时间21222324
先来个小例子:
运行结果:
Parent process run. subProcess is 30196
Parent process end,Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:21 2017
subProcess 30196 run, Mon Mar 27 11:20:23 2017
subProcess 30196 run, Mon Mar 27 11:20:25 2017
根据运行结果可知,父进程运行结束后子进程仍然还在运行,这可能造成僵尸( zombie)进程。
通常情况下,当子进程终结时,它会通知父进程,清空自己所占据的内存,并在内核里留下自己的退出信息。父进程在得知子进程终结时,会从内核中取出子进程的退出信息。但是,如果父进程早于子进程终结,这可能造成子进程的退出信息滞留在内核中,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。
有什么办法可以避免僵尸进程呢?
这里介绍进程的一个属性 deamon,当其值为TRUE时,其父进程结束,该进程也直接终止运行(即使还没运行完)。
所以给上面的程序加上p.deamon = true,看看效果。
执行结果:
Parent process run. subProcess is 31856
Parent process end,Mon Mar 27 11:40:10 2017
这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢?
这里引入p.join()方法,它使子进程执行结束后,父进程才执行之后的代码
执行结果:
subProcess 32076 run, Mon Mar 27 11:46:07 2017
subProcess 32076 run, Mon Mar 27 11:46:09 2017
subProcess 32076 run, Mon Mar 27 11:46:11 2017
Parent process run. subProcess is 32076
Parent process end,Mon Mar 27 11:46:13 2017
这样所有的进程就能顺利的执行了。
将进程定义成类
通过继承Process类,来自定义进程类,实现run方法。实例p通过调用p.start()时自动调用run方法。
如下:
执行结果和上一个例子相同。
创建多个进程
很多时候系统都需要创建多个进程以提高CPU的利用率,当数量较少时,可以手动生成一个个Process实例。当进程数量很多时,或许可以利用循环,但是这需要程序员手动管理系统中并发进程的数量,有时会很麻烦。这时进程池Pool就可以发挥其功效了。可以通过传递参数限制并发进程的数量,默认值为CPU的核数。
直接上例子:
执行结果:
开头部分
Run the main process (30920).
Waiting for all subprocesses done …
Run child process Process0 (32396)
Run child process Process3 (25392)
Run child process Process1 (28732)
Run child process Process2 (32436)
末尾部分:
Run child process Process15 (25880)
All subprocesses done
All process last 2.49 seconds.
相关说明:
这里进程池对并发进程的限制数量为8个,而程序运行时会产生16个进程,进程池将自动管理系统内进程的并发数量,其余进程将会在队列中等待。限制并发数量是因为,系统中并发的进程不是越多越好,并发进程太多,可能使CPU大部分的时间用于进程调度,而不是执行有效的计算。
采用多进程并发技术时,就单个处理机而言,其对进程的执行是串行的。但具体某个时刻哪个进程获得CPU资源而执行是不可预知的(如执行结果的开头部分,各进程的执行顺序不定),这就体现了进程的异步性。
如果单个程序执行14次run_proc函数,那么它会需要至少16秒,通过进程的并发,这里只需要2.49秒,可见并发的优势。
‘陆’ 如何判断并杀掉超时的python进程
supervisord专门干的就是这事,这个已经很成熟,服务器上的Python和MongoDB进程都是用它管理的。 如果supervisord还不满足你的需求,如你需要在自己的程序中进行进程管理,你可以去参考supervisord的代码实现。 简单的,可以自己用 http://docs.python.org/library/subprocess.html去实现自己的一套。
‘柒’ 如何让 Python 代码常驻在服务器进程中
一、nohup
nohup,即 no hangup,nohup 的用途就是让提交的命令忽略 hangup 信号,从而使我们的进程避免中途被中断。它可以让 python 脚本和服务器连接端的 session 分离,以达到退出后依旧执行:
$ chmod +x /your_path/yourscript.py # 先设置可执行权限$ nohup python /your_path/yourscript.py# 切记退出的 Terminal 的时候,不要 ctrl+c 退出,而是直接关闭,不然 Nohup 就被你关闭了。
如何关闭这个一直执行的进程呢:
# 找到对应的进程 PID
$ ps -ef | grep python
# 返回内容如:
user 2430 1 0 Jul03 ? 00:00:01 /usr/bin/python -tt /usr/sbin/yum-updatesd
# kill 掉该进程即可:
$ kill -9 2430
PS:nohup 在服务器重启之后就失效了,所以并不完美。
二、将命令写入 Linux 启动脚本
Linux 在启动的时候会执行 /etc/rc.local 里面的脚本,所以只要在这里添加执行命令就可以:
$ vim /etc/rc.local
# 如果是 Centos 添加以下内容:
/your_path/python3.4 /your_path/yourscript.py
# 以上内容需要添加在 exit 命令前,而且由于在执行 rc.local 脚本时,PATH 环境变量未全部初始化,因此命令需要使用绝对路径。
PS:这种方式的缺点是如果脚本挂了,那么不会自动重新启动。
三、使用 Supervisor 进程管理工具
详见这篇文章:使用 Supervisor 管理服务器后台进程,在服务器重启和脚本出错后,可以完美重启,推荐。
‘捌’ python 关闭正在运行的python进程
打开任务管理器(右键任务栏)关闭
‘玖’ python怎么获取自身进程的CPU和内存使用情况
这个需要进进程管理查看 如何打开进程管理器 快捷键Ctrl+Alt+方向键下键(或者小键盘的Enter键)
‘拾’ 如何使用Python的Supervisor来管理进程
在python开发中,如何使用supervisor来管理进程呢?Supervisor是什么?Supervisor是如何管理进程的,现在就跟随小编一起来看看使用python的supervisor管理经常的方法。
Supervisor可以启动、停止、重启*nix系统中的程序。也可以重启崩溃的程序。
supervisord的一个守护进程,用于将指定的进程当做子进程来运行。
supervisorctl是一个客户端程序,可以查看日志并通过统一的会话来控制进程。
看例子:
我们写了一个py脚本,用于往log文件中记录一条当前的时间。
[python]view plain
1.root@ubuntu:/home/zoer#catdaemon.py
2.#!/usr/bin/envpython
3.
4.importtime
5.importos
6.time.sleep(1)
7.f=open("log",'a')
8.t=time.time()
9.f.write(str(t))
10.f.write("\n")
11.f.close()
安装过程就不说了。
安装完毕supervisor之后【将配置文件放在/etc下】。修改配置文件,在最后增加如下内容:
[program:ddd]
command=/home/zoer/daemon.py
autorestart=true
然后我们启动supervisor并启动daemon.py的执行。
[python]view plain
1.root@ubuntu:/home/zoer#supervisord
2./usr/local/lib/python2.7/dist-packages/supervisor-3.0b1-py2.7.egg/supervisor/options.py:286:UserWarning:aultlocations();youprobablywanttospecifya"-c"y.
3.''
4.root@ubuntu:/home/zoer#supervisorctl
5.dddSTARTING
6.supervisor>startddd
7.ddd:ERROR(alreadystarted)
8.supervisor>stopddd
9.ddd:stopped
10.supervisor>startddd
11.ddd:started
12.supervisor>
从上面的例子中,看到,可以通过start或者stop命令来启动或者停止ddd这个进程。ddd这里就是我们在配置文件中增加的内容(daemon.py这个脚本)。
也可以使用restart。如下:
supervisor> restart ddd
ddd: stopped
ddd: started
-------------------------------------------------------
下面我们测试一下,假设说我们手动kill掉了ddd这个进程,那么ddd会自动恢复执行吗?
为了做实验,把代码修改如下:
[python]view plain
1.root@ubuntu:/home/zoer#catdaemon.py
2.#!/usr/bin/envpython
3.
4.importtime
5.importos
6.whileTrue:
7.time.sleep(1)
8.f=open("log",'a')
9.t=time.time()
10.f.write(str(t))
11.f.write("\n")
12.f.close()
通过ps可以找到这个进程的id:
[plain]view plain
1.root93540.20.4109244200?S23:160:00python/home/zoer/daemon.py
2.root93950.00.04392832pts/3S+23:170:00grep--color=autodaemon
3.root@ubuntu:/home/zoer#
看下面的操作:
[plain]view plain
1.root@ubuntu:/home/zoer#rmlog;touchlog;kill9354
2.root@ubuntu:/home/zoer#catlog
3.1364710712.51
4.root@ubuntu:/home/zoer#catlog
5.1364710712.51
6.1364710713.51
7.root@ubuntu:/home/zoer#catlog
8.1364710712.51
9.1364710713.51
10.root@ubuntu:/home/zoer#catlog
11.1364710712.51
12.1364710713.51
13.1364710714.52
14.root@ubuntu:/home/zoer#catlog
15.1364710712.51
16.1364710713.51
17.1364710714.52
18.1364710715.52
删除了log文件,并且重新创建。然后干掉了daemon.py的那个进程。会发现log内容又重新有新的内容了。再次ps查看进程号。
[plain]view plain
1.root94290.10.4109244200?S23:180:00python/home/zoer/daemon.py
2.root94400.00.04392828pts/3S+23:190:00grep--color=autodaemon
3.root@ubuntu:/home/zoer#
会发现进程号已经变成9429了。说明supervisor已经重启了被干掉了的进程。