python技巧-使用 faulthandler 模块获取运行中进程的 traceback 信息

python技巧-使用 faulthandler 模块获取运行中进程的 traceback 信息,第1张

Python 33 新增了一个 faulthandler 模块,可以输出运行中进程的 traceback 信息,可以用来作为调试运行中的 Python 进程的一种手段。

模块本身是使用 C 实现的,所以有如下特点和限制:

Python 33 自带了这个模块,Python 2x 可以通过一下方式安装:

测试函数:

使用 faulthandler 输出所有线程的 traceback 信息:

首先你要搞清楚进程和线程的关系:线程是最小的执行单元,而进程由至少一个线程组成。

multiprocessing模块是一个跨平台版本的多进程模块。该模块提供了process类来代表一个进程对象。

Process

构造方法__init__(self, group=None, target=None, name=None, args=(), kwargs={})

参数说明:

group:进程所属组。基本不用

target:表示调用对象或方法名称。

args:表示调用对象的位置参数元组。

name:别名

kwargs:表示调用对象的字典。

示例代码如下:

threading本身就可以创建多个线程:

hreads = []#定义一个线程池

t1 = threadingThread(target=one,args=(,))#建立一个线程并且赋给t1,这个线程指定调用方法one,并且不带参数

threadsappend(t1)#把t1线程装到threads线程池里

t2 = threadingThread(target=two)

threadsappend(t2)

t3 = threadingThread(target=three)

threadsappend(t3)

这时threads这个列表中就有三个线程装在里面了。

下面就是运行这个线程池里面的线程

for t in threads:

用一个for语句遍历threads里的线程,然后调用start()方法运行

注意tjoin()必须放在for语句外面。

想要充分利用多核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," % osgetpid(), "{0}"format(timectime())    #获取当前进程号和正在运行是的时间

       timesleep(wTime)    #等待(休眠)

       n += 1if __name__ == "__main__":

   p = Process(target=run_proc, args=(2,))  #申请子进程

   pstart()     #运行进程

   print "Parent process run subProcess is ", ppid    print "Parent process end,{0}"format(timectime())12345678910111213141516171819

运行结果:

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时,其父进程结束,该进程也直接终止运行(即使还没运行完)。 

所以给上面的程序加上pdeamon = true,看看效果。

# -- coding:utf-8 --from multiprocessing import Process, Poolimport osimport timedef run_proc(wTime):

   n = 0

   while n < 3:        print "subProcess %s run," % osgetpid(), "{0}"format(timectime())

       timesleep(wTime)

       n += 1if __name__ == "__main__":

   p = Process(target=run_proc, args=(2,))

   pdaemon = True    #加入daemon

   pstart()    print "Parent process run subProcess is ", ppid    print "Parent process end,{0}"format(timectime())1234567891011121314151617181920

执行结果:

Parent process run subProcess is 31856 

Parent process end,Mon Mar 27 11:40:10 2017

这是问题又来了,子进程并没有执行完,这不是所期望的结果。有没办法将子进程执行完后才让父进程结束呢? 

这里引入pjoin()方法,它使子进程执行结束后,父进程才执行之后的代码

# -- coding:utf-8 --from multiprocessing import Process, Poolimport osimport timedef run_proc(wTime):

   n = 0

   while n < 3:        print "subProcess %s run," % osgetpid(), "{0}"format(timectime())

       timesleep(wTime)

       n += 1if __name__ == "__main__":

   p = Process(target=run_proc, args=(2,))

   pdaemon = True

   pstart()

   pjoin()    #加入join方法

   print "Parent process run subProcess is ", ppid    print "Parent process end,{0}"format(timectime())123456789101112131415161718192021

执行结果:

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通过调用pstart()时自动调用run方法。 

如下:

# -- coding:utf-8 --from multiprocessing import Process, Poolimport osimport timeclass Myprocess(Process):

   def __init__(self, wTime):

       Process__init__(self)

       selfwTime = wTime    def run(self):

       n = 0

       while n < 3:            print "subProcess %s run," % osgetpid(), "{0}"format(timectime())

           timesleep(selfwTime)

           n += 1if __name__ == "__main__":

   p = Myprocess(2)

   pdaemon = True

   pstart()    #自动调用run方法

   pjoin()    print "Parent process run subProcess is ", ppid    print "Parent process end,{0}"format(timectime())12345678910111213141516171819202122232425262728

执行结果和上一个例子相同。

创建多个进程

很多时候系统都需要创建多个进程以提高CPU的利用率,当数量较少时,可以手动生成一个个Process实例。当进程数量很多时,或许可以利用循环,但是这需要程序员手动管理系统中并发进程的数量,有时会很麻烦。这时进程池Pool就可以发挥其功效了。可以通过传递参数限制并发进程的数量,默认值为CPU的核数。 

直接上例子:

# -- coding:utf-8 --from multiprocessing import Process,Poolimport os,timedef run_proc(name):        ##定义一个函数用于进程调用

   for i in range(5):    

       timesleep(02)    #休眠02秒

       print 'Run child process %s (%s)' % (name, osgetpid())#执行一次该函数共需1秒的时间if __name__ =='__main__': #执行主进程

   print 'Run the main process (%s)' % (osgetpid())

   mainStart = timetime() #记录主进程开始的时间

   p = Pool(8)           #开辟进程池

   for i in range(16):                                 #开辟14个进程

       papply_async(run_proc,args=('Process'+str(i),))#每个进程都调用run_proc函数,

                                                       #args表示给该函数传递的参数。

   print 'Waiting for all subprocesses done '

   pclose() #关闭进程池

   pjoin()  #等待开辟的所有进程执行完后,主进程才继续往下执行

   print 'All subprocesses done'

   mainEnd = timetime()  #记录主进程结束时间

   print 'All process ran %02f seconds' % (mainEnd-mainStart)  #主进程执行时间123456789101112131415161718192021222324

执行结果: 

开头部分

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 249 seconds

相关说明:

这里进程池对并发进程的限制数量为8个,而程序运行时会产生16个进程,进程池将自动管理系统内进程的并发数量,其余进程将会在队列中等待。限制并发数量是因为,系统中并发的进程不是越多越好,并发进程太多,可能使CPU大部分的时间用于进程调度,而不是执行有效的计算。

采用多进程并发技术时,就单个处理机而言,其对进程的执行是串行的。但具体某个时刻哪个进程获得CPU资源而执行是不可预知的(如执行结果的开头部分,各进程的执行顺序不定),这就体现了进程的异步性。

如果单个程序执行14次run_proc函数,那么它会需要至少16秒,通过进程的并发,这里只需要249秒,可见并发的优势。

以上就是关于python技巧-使用 faulthandler 模块获取运行中进程的 traceback 信息全部的内容,包括:python技巧-使用 faulthandler 模块获取运行中进程的 traceback 信息、python 多线程和多进程的区别 mutiprocessing theading、python怎么实现一个进程等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9598510.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-30
下一篇2023-04-30

发表评论

登录后才能评论

评论列表(0条)

    保存