2

I'm running the code below. From terminal I'm putting python test.py. But it's giving me nothing.

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

def hello():
    print "Hello"

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

I tried the same code in a different machine, it's showing me the output properly. I tried going step by step. I kept only the print statement and it's working fine. Then I added that print to a function, and called the function, it is also working fine. As soon as I add the Timer, the python command keeps on running without showing any output, until I stop it by force.

Previously the same thing happened with scapy library. But after a system restart it worked fine. But now it is not working after the system restart also.

What could be the problem?

Note 1: 6 days back, it was not behaving like this. Is there any chance of any malwares?

Note 2: A peculiar behaviour.

###test.py### Version 1

from threading import Timer
from time import sleep

def hello():
    print "Hello"

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

This was my version 1. After it didn't work, I modified it to Version 2 which is mentioned above. Still no output. But when I press ctrl+c, It's showing

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

Though that line of code is not present there. I rechecked the saved file whether I saved or not. I also checked whether any pyc file is creating trouble or not. But no pyc was there.

RatDon
  • 3,403
  • 8
  • 43
  • 85
  • It would help if you mentioned the Python version and platform (distro and version, not just "linux"). – abarnert Apr 20 '15 at 05:55
  • Just to make sure: Is this the Python 2.7 that comes with Fedora (or that's part of the core repo, if 21 has make 2.7 an optional install already)? – abarnert Apr 20 '15 at 06:08
  • No. it's the one that comes with Fedora. – RatDon Apr 20 '15 at 06:10
  • Do you have a file named either `time.py` or `threading.py` (or, did you used to have one, and still have `time.pyc` or `threading.pyc`) in the same directory as `test.py`, or anywhere else on your `sys.path`? – abarnert Apr 20 '15 at 06:29
  • I did a `rm *.pyc`. But there was no `pyc` files in that directory. Recently I've not installed any application or modified `sys.path`. So I guess, it is intact. It's not only with `threading` or `time`. With `scapy` also it behaves the same. – RatDon Apr 20 '15 at 06:33
  • 1
    Yeah, but I'm sure `scapy` uses `time`. Again, check whether there's a file named `time.py` in the current directory. Or look at the answer I just added for a simple foolproof test. – abarnert Apr 20 '15 at 06:34

2 Answers2

1

You have a file named time.py in the same directory as test.py. (Or you did have one, and still have time.pyc. Or you have some somewhere else in your sys.path for some reason.)

When you do import time or from time import sleep, it's not opening the stdlib's time, it's opening your time.py.

And even if you don't do that, inside threading:*

from time import time as _time, sleep as _sleep

So, if your time.py doesn't have a sleep method, this will just raise an exception. But if it does, that's when things get fun. Everything will seem to work fine, until the Timer thread sleeps for 5 seconds by (ultimately) calling a block-and-spin loop inside Condition.wait. If your time.sleep function isn't actually sleeping, or if it multiplies the sleep time by 1000, or whatever, that could cause it to burn up 100% CPU busy-waiting, or to take much longer than 5 seconds to fire, or who knows what.

Likewise, scapy is almost certainly using the time module, which is why it's having the same problem.


At any rate, you can test this pretty easily:

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

If the results aren't similar to that, there's your problem.


* The copy of 2.7.6 I have lying around is slightly different, but I assume Fedora 21 will be closer to the latest 2.7 trunk than 2.7.6, so that's what I linked to… At any rate, the differences don't matter.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thanks. There was a trace of `time.pyc`. I deleted that. and it worked fine. Quick question. `import time` or `from time import sleep` were not there, still why it was trying to import them? is it due to the `Timer`? – RatDon Apr 20 '15 at 06:37
0

Python doesn't document anywhere what happens if the main thread exits while non-daemon background threads are running. In practice, at least CPython implicitly joins them at some point—but it may do some cleanup first. Which could possibly involve closing sys.stdout.*

In fact, if you look at the 2.7 source for threading, it explicitly stashes stderr at launch specifically to make sure it can still print exception tracebacks if the main thread has already closed sys.stderr.

So, what you're trying to do isn't supposed to work reliably. If you want to make sure absolutely background threads (including those running Timers) have full access to all the normal runtime stuff, you need to keep the main thread running—usually by joining them. (Yes, you can call join on a Timer; as the docs say, "Timer is a subclass of Thread.")


* The details of where and how this happens have changed multiple times, and I don't remember exactly how 2.7 did it. Originally it was just a __del__ method on a special _MainThread object that gets created to represent the main thread as soon as any other thread is started, but later there was an atexit handler, then special support to call threading._shutdown if it exists, then it was changed again to fit the module-unloading fixes…

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • with `join` also it's not working. I tried with `time.sleep(10)` in the main thread too. No result. – RatDon Apr 20 '15 at 06:06
  • @RatDon: Just to take rule out anything funky with `Timer`, can you just `def hello(): time.sleep(5); print 'Hello'` then create a `threading.Thread(target=hello)` instead of a `threading.Timer`? It _should_ have exactly the same effect, but… let's see if it does. – abarnert Apr 20 '15 at 06:07
  • @RatDon: Also, try replacing the `print 'Hello'` with `raise Exception('Does my traceback get printed?')`. – abarnert Apr 20 '15 at 06:09
  • @RatDon: One last thing: with both `t.join()` and `time.sleep(10)` in the main thread, if you put a `print 'Main thread done waiting" right after that, does it get printed? – abarnert Apr 20 '15 at 06:18
  • Updated the question with some of my observation. Have a look at it. I'll test whatever you said and will update it. – RatDon Apr 20 '15 at 06:24