I'd never thought about this, so I wrote this script:
import time
while True:
print "loop"
time.sleep(0.5)
Just as a test. Running this with strace -o isacontextswitch.strace -s512 python test.py
gives you this output on the loop:
write(1, "loop
", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop
", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop
", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop
", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop
", 5)
select()
is a system call, so yes, you are context switching (ok technically a context switch is not actually necessary when you change to kernel space, but if you have other processes running, what you're saying here is that unless you have data ready to read on your file descriptor, other processes can run until then) into the kernel in order to perform this. Interestingly, the delay is in selecting on stdin. This allows python to interrupt your input on events such as ctrl+c
input, should they wish, without having to wait for the code to time out - which I think is quite neat.
I should note that the same applies to time.sleep(0)
except that the time parameter passed in is {0,0}
. And that spin locking is not really ideal for anything but very short delays - multiprocessing
and threads
provide the ability to wait on event objects.
Edit: So I had a look to see exactly what linux does. The implementation in do_select
(fsselect.c
) makes this check:
if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {
wait = NULL;
timed_out = 1;
}
if (end_time && !timed_out)
slack = select_estimate_accuracy(end_time);
In other words, if an end time is provided and both parameters are zero (!0 = 1 and evaluates to true in C) then the wait is set to NULL and the select is considered timed out. However, that doesn't mean the function returns back to you; it loops over all the file descriptors you have and calls cond_resched
, thereby potentially allowing another process to run. In other words, what happens is entirely up to the scheduler; if your process has been hogging CPU time compared to other processes, chances are a context switch will take place. If not, the task you are in (the kernel do_select function) might just carry on until it completes.
I would re-iterate, however, that the best way to be nicer to other processes generally involves using other mechanisms than a spin lock.