raspbian python代码冻结

时间:2015-02-18 19:24:58

标签: python raspberry-pi raspbian

我正在运行一个python代码来进行一些网页报废,这意味着代码偶尔会将数据写入(附加)到文本文件中。有时代码会冻结,但Shell中不会显示任何错误消息。 我想知道这是否更有可能是因为raspbian系统不可靠,或者是因为我的代码存在一些隐藏的问题。

1 个答案:

答案 0 :(得分:4)

very good rule of thumb是故障始终在您自己的代码中而不在系统中。特别是,如果系统的其余部分正在运行(即您可以使用另一个控制台),那么几乎可以肯定是您的程序挂起的错误。

在运行进程的shell中,尝试按 Ctrl + C 以询问进程是否停止,或者 Ctrl + \ 完全放弃它。您应该收到一条错误消息,显示您终止程序时的位置。让我们假设你的程序是

x = 0
def bar():
    return x * 2
def foo():
    x = 11
    while bar() < 100:
        x += 1

foo()

(你能否发现错误?)我现在用python program.py运行它,但它挂起并且没有终止。按 Ctrl + C 会产生:

^CTraceback (most recent call last):
  File "python.py", line 9, in <module>
    foo()
  File "python.py", line 6, in foo
    while bar() < 100:
  File "python.py", line 3, in bar
    return x * 2
KeyboardInterrupt

^C Ctrl + C 的直观表示,可以忽略。其余的是stack trace,它显示了程序在运行时所执行的操作。为了获得良好的效果,请多次中断您的程序并比较堆栈跟踪,以查看#34;悬挂&#34;。

时的通常情况。

此外,使用更多调试输出扩展程序(可能由新开关切换),这样您就不需要首先打断它。一个好主意是在连接到网络之前和之后总是输出一些东西。

由于你在网络上,另一方也可能只是默默地死去,你的程序可能会等待一段时间来确认发生了什么(而不是因为接收不良或网络拥塞严重)。您可以使用较低的值来调用socket.setdefaulttimeout,以使您的程序提前退出,而不是等待对方说些什么。

您还可以使用各种工具来帮助调试。例如,键入htopsudo apt-get install -y htop一次安装它,如果您还没有,或top也可以),以查看您的计划进展情况。查看CPU负载系数(位于最顶层)以及列出程序的位置。

说它看起来像这样:

CPU |||             8.0%

尽管按CPU排序(按 F6 进行排序),我们的程序甚至没有显示在这里,而htop是唯一使用大部分CPU的程序。这意味着我们的程序(如果它正在运行)卡在system call中,即已经对操作系统产生了控制权。但由于操作系统也没有使用太多CPU(其CPU使用率以红色映射),看起来我们正在等待某些东西!

另一方面,htop输出我的样子:

CPU ||||||||||||||| 100%

您会注意到program.py功能突出。这也不是因为我们的程序以任何方式强调操作系统,因为条形图基本上都是绿色的!

然后你可能想要比仅仅查看聚合值或杀死聚合值更好地调查程序的当前状态。有很多工具,但让我们看看两个:

strace 实用程序(再次使用sudo apt-get install -y strace安装一次)可以显示程序所进行的系统调用。这适用于每个程序,而不仅仅是Python程序。在我们简单的示例程序上运行它会产生:

$ strace -o log python program.py 
execve("/usr/bin/python", ["python", "program.py"], [/* 47 vars */]) = 0
brk(0)                                  = 0x218f000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fbb72742000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
* snip about 1000 lines*
read(3, "x = 0\ndef bar():\n    return x * "..., 4096) = 101
lseek(3, 101, SEEK_SET)                 = 101
brk(0x291d000)                          = 0x291d000
read(3, "", 4096)                       = 0
brk(0x2914000)                          = 0x2914000
close(3)                                = 0
munmap(0x7f7b9d294000, 4096)            = 0

如果需要,您也可以将其作为strace -o logfile python program.py运行,将输出写入./logfile,以便您可以在另一个shell中检查它,例如使用文本编辑器。

我们在这里看到Python即使只是启动也需要很多的系统调用,但我们的程序根本不会进行系统调用!我们看到,因为最后一次系统调用是源代码文件中的Python读取。使用不同的程序,输出可能看起来像

socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("93.184.216.34")}, 16) = 0
recvfrom(3, 

最重要的部分是未完成的最后一行,表明操作系统目前处于控制状态。操作系统在做什么?好吧,它正在致电recvfrom或等待数据。由于它只是在等待并且实际上没有做太多,所以htop只显示可忽略不计的红条。如果操作系统中有错误,htop现在会显示很多红色。

现在,我们如何知道哪个系统调用来自哪个Python语句?为此,我们需要一个Python调试器。您的IDE可能有一个集成,但在紧要关头,内置pdb可以工作。让我们在我们的(新)程序上运行它:

$ pdb program2.py 
> /home/phihag/tmp/stackoverflow/program2.py(1)<module>()
-> import socket
(Pdb) next
> /home/phihag/tmp/stackoverflow/program2.py(3)<module>()
-> c = socket.create_connection(('example.net', 80))
(Pdb) n
> /home/phihag/tmp/stackoverflow/program2.py(4)<module>()
-> while True:
(Pdb) n
> /home/phihag/tmp/stackoverflow/program2.py(5)<module>()
-> print(c.recv(1024))
(Pdb) n

使用nextstep(或简短ns)来逐步完成该计划(对于大型程序,您最有可能需要continue和一个断点)。输入help pdb以查看pdb帮助信息。在这种情况下,我们看到程序当前挂起的行是第5行(print(c.recv(1024)))。

现在,如果你不理解为什么你的程序挂起,上面的调试工具应该为你提供大量信息来创建minimal, complete, verifiable example

一旦您确认 挂起,请随时ask a stackoverflow question关于它。