首页 > 编程知识 正文

python 统计分析(python关闭进程)

时间:2023-05-03 20:30:22 阅读:1497 作者:2411

要在Java中打印当前线程的方法栈,可以用kill -3命令向JVM发送一个OS信号,JVM捕获后会自动转储。当然,也可以直接使用jstack工具来完成,几年前我在这篇性能分析文章中介绍了jstack工具。这样的需求可以说是非常常见的,比如定位死锁,定位一个非工作线程到底卡在哪里,或者定位为什么CPU保持高位等等。

现在我在工作中使用Python,因为我需要定位在线问题,我也有类似的需求。——想知道当前Python进程在做什么。但是没有JVM的加持,原来的命令或者工具就不再适用了。传统gdb的调试方案也不容易在线操作。所以我寻找一些其他的方法来帮助定位问题,我把它们记录在这里。

信号

在代码中,我们可以使用signal为进程预注册一个信号接收器,当进程接收到特定信号时,我们可以打印方法堆栈:

导入追溯,信号

类调试器():

def __init__(自我,记录器):

自我。_logger=logger

def log_stack_trace(自,sig,帧):

d={'_frame':frame}

d.update(frame.f_globals)

d . update(frame . f _ local)

消息='收到信号。堆栈跟踪:n '

消息=' '。连接(回溯. format_stack(frame))

自我。_logger.warn(消息)

def监听(自):

信号。SIGUSR1,self.log_stack_trace)

通过调用上面的监听方法(比如新的Debug(记录器))。listen()),可以接收SIGUSR1并打印方法堆栈的接收器在当前进程中注册。这里是print方法堆栈,但实际上你可以做任何事情,因为方法执行的当前上下文已经运行到流程中。

那么如何向这个过程发送信号呢?类似于JVM方法,它可以通过操作系统命令发送:

kill -30 pid

为什么这里的信号是30?这是因为SIGUSR1被当前操作系统定义为30(请注意这个映射表对于不同的操作系统可能是不同的),可以通过man signal查看:

无名称默认操作描述

1 SIGHUP终止过程终端线路挂断

2 SIGINT终止进程中断程序

3 SIGQUIT创建核心映像退出程序

4 SIGILL创建核心映像非法指令

5 SIGTRAP创建核心映像跟踪陷阱

6 SIGABRT创建核心映像中止程序(以前为SIGIOT)

7执行SIGEMT创建核心映像仿真指令

8 SIGFPE创建核心映像浮点异常

9 SIGKILL终止进程终止程序

10 SIGBUS创建核心映像总线错误

11 SIGSEGV创建核心图像分割违规

12 SIGSYS创建核心映像不存在的系统调用被调用

13 SIGPIPE在没有读取器的管道上终止进程写入

14 SIGALRM终止进程实时定时器到期

15 SIGTERM终止过程软件终止信号

16插座上出现SIGURG丢弃信号紧急情况

17 SIGSTOP停止进程停止(不能被捕获或忽略)

18 SIGTSTP停止从键盘产生的进程停止信号

19停止后继续SIGCONT丢弃信号

20 SIGCHLD丢弃信号子状态发生变化

d 21 SIGTTIN stop process background read attempted from control terminal 22 SIGTTOU stop process background write attempted to control terminal 23 SIGIO discard signal I/O is possible on a descriptor (see fcntl(2)) 24 SIGXCPU terminate process cpu time limit exceeded (see setrlimit(2)) 25 SIGXFSZ terminate process file size limit exceeded (see setrlimit(2)) 26 SIGVTALRM terminate process virtual time alarm (see setitimer(2)) 27 SIGPROF terminate process profiling timer alarm (see setitimer(2)) 28 SIGWINCH discard signal Window size change 29 SIGINFO discard signal status request from keyboard 30 SIGUSR1 terminate process User defined signal 1 31 SIGUSR2 terminate process User defined signal 2

当然,也可以写一点点 python 脚本来发送这个信号:

import os, signal os.kill($PID, signal.SIGUSR1)

原理是一样的。

strace

如果进程已经无响应了,或者上面的信号接收器没有注册,那么就要考虑别的方法来或者“进程在干什么”这件事情了。其中,一个有用的命令是 strace:

strace -p pid

比如,我自己写了一个测试脚本 t.py,使用 python 执行,然后调用 sleep,再给它发送一个 SIGUSR1 的消息,它打印方法栈并退出。这整个过程,我使用 strace 可以得到这样的结果:

strace -p 9157 strace: Process 9157 attached select(0, NULL, NULL, NULL, {9999943, 62231}) = ? ERESTARTNOHAND (To be restarted if no handler) --- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, si_pid=9273, si_uid=9007} --- rt_sigreturn({mask=[]}) = -1 EINTR (Interrupted system call) stat("t.py", {st_mode=S_IFREG|0644, st_size=1281, ...}) = 0 open("t.py", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=1281, ...}) = 0 fstat(3, {st_mode=S_IFREG|0644, st_size=1281, ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f631e866000 read(3, "import traceback, signal, timen "..., 8192) = 1281 read(3, "", 4096) = 0 close(3) = 0 munmap(0x7f631e866000, 4096) = 0 stat("t.py", {st_mode=S_IFREG|0644, st_size=1281, ...}) = 0 write(1, "Signal received. Stack trace:n "..., 134) = 134 write(1, "n", 1) = 1 rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f631e06f5d0}, {0x7f631e392680, [], SA_RESTORER, 0x7f631e06f5d0}, 8) = 0 rt_sigaction(SIGUSR1, {SIG_DFL, [], SA_RESTORER, 0x7f631e06f5d0}, {0x7f631e392680, [], SA_RESTORER, 0x7f631e06f5d0}, 8) = 0 exit_group(0) = ? +++ exited with 0 +++

可以看到从 strace attached 开始,到进程退出,所有重要的调用都被打印出来了。

在 iOS 下,没有 strace,但是可以使用类似的(更好的)命令 dtruss。

lsof

lsof 可以打印某进程打开的文件,而 Linux 下面一切都是文件,因此查看打开的文件列表有时可以获取很多额外的信息。比如,打开前面提到的这个测试进程:

lsof -p 16872 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME Python 16872 xxx cwd DIR 1,5 2688 1113586 /Users/xxx Python 16872 xxx txt REG 1,5 51744 10627527 /System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python Python 16872 xxx txt REG 1,5 52768 10631046 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_locale.so Python 16872 xxx txt REG 1,5 65952 10631134 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/time.so Python 16872 xxx txt REG 1,5 841440 10690598 /usr/lib/dyld Python 16872 xxx txt REG 1,5 1170079744 10705794 /private/var/db/dyld/dyld_shared_cache_x86_64h Python 16872 xxx 0u CHR 16,2 0t39990 649 /dev/ttys002 Python 16872 xxx 1u CHR 16,2 0t39990 649 /dev/ttys002 Python 16872 xxx 2u CHR 16,2 0t39990 649 /dev/ttys002

它有几个参数很常用,比如-i,用来指定网络文件(如果是“-i: 端口号”这样的形式还可以指定端口)。最后dtdld个人有六年开发经验,我自己有做python材料的整合,一个完整的python编程学习路线,学习资料和工具。想要这些资料的可以关注小编,并在后台私信:发送“01”领取,希望能帮助到你。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。