2

我正在运行下面的代码。从终端我把python test.py. 但它什么也没给我。

###test.py### Version 2
from threading import Timer

def hello():
    print "Hello"

t=Timer(5, hello)
t.start()

我在另一台机器上尝试了相同的代码,它正确地向我显示了输出。我试着一步一步来。我只保留了print声明,它工作正常。然后我将该 print 添加到一个函数中,并调用该函数,它也可以正常工作。一旦我添加了Timer,python 命令就会继续运行而不显示任何输出,直到我强行停止它。

scapy以前图书馆也发生过同样的事情。但是在系统重启后它工作正常。但是现在系统重新启动后它也不起作用。

可能是什么问题呢?

注 1: 6 天前,它的行为不是这样的。是否有任何恶意软件的机会?

注2:一种特殊的行为。

###test.py### Version 1

from threading import Timer
from time import sleep

def hello():
    print "Hello"

t=Timer(5, hello)
t.start()
sleep(10)

这是我的第1版。它不起作用后,我将其修改为上面提到的第2版。还是没有输出。但是当我按ctrl+时c,它正在显示

  from time import sleep as _sleep
 File .........., line 2, in <module>
KeyboardInterrupt

尽管那里不存在那行代码。我重新检查了保存的文件是否保存。我还检查了是否有任何pyc文件造成麻烦。但是没有pyc

4

2 回答 2

1

您有一个名为 的文件time.py在同一目录中test.py。(或者你确实有一个,并且仍然有。或者你出于某种原因time.pyc在你的其他地方有一些。)sys.path

当您执行import timeorfrom time import sleep时,它不是打开 stdlib 的time,而是打开您的time.py.

即使你不这样做,里面threading*

from time import time as _time, sleep as _sleep

所以,如果你time.py没有sleep方法,这只会引发异常。但如果确实如此,那就是事情变得有趣的时候。一切似乎都可以正常工作,直到Timer线程通过(最终)调用内部的块和自旋循环休眠 5 秒Condition.wait。如果您的time.sleep函数实际上并未处于睡眠状态,或者它将睡眠时间乘以 1000 或其他什么,这可能会导致它烧毁 100% 的 CPU 忙等待,或者触发时间超过 5 秒,或者谁知道什么。

同样,scapy几乎可以肯定是在使用该time模块,这就是它遇到同样问题的原因。


无论如何,您可以很容易地对此进行测试:

$ python2.7
>>> import time
>>> time.__file__
/usr/lib/python2.7/lib-dynload/time.so
>>> import threading
>>> threading.__file__
/usr/lib/python2.7/threading.pyc

如果结果与此不相似,那就是你的问题。


* 我身边的 2.7.6 副本略有不同,但我认为 Fedora 21 将比 2.7.6 更接近最新的 2.7 主干,所以这就是我所链接的……无论如何,差异并不重要.

于 2015-04-20T06:33:23.027 回答
0

如果在非守护进程后台线程运行时主线程退出,Python 不会在任何地方记录会发生什么。在实践中,至少 CPythonjoin会在某些时候隐含它们——但它可能会先进行一些清理。这可能涉及关闭sys.stdout*

实际上,如果您查看2.7 的源代码threading,它会在启动时显式存储stderr,以确保在主线程已经关闭的情况下仍然可以打印异常回溯sys.stderr

因此,您尝试做的事情不应该可靠地工作。如果你想确保绝对后台线程(包括那些正在运行Timer的线程)可以完全访问所有正常运行时的东西,你需要保持主线程运行——通常是通过joining 来运行它们。join(是的,您可以调用Timer; 正如文档所说,“Timer是 的子类Thread。”)


* 发生这种情况的地点和方式的细节已经多次更改,我不记得 2.7 是如何做到的。最初它只是一个__del__特殊_MainThread对象上的一个方法,一旦任何其他线程启动,它就会被创建以表示主线程,但后来有一个 atexit 处理程序,然后特殊支持调用threading._shutdown如果它存在,然后它再次更改为适合模块卸载修复...</sub>

于 2015-04-20T05:55:02.080 回答