我从没想过,所以我写了这个剧本:import time
while True:
print "loop"
time.sleep(0.5)
只是个测试。使用strace -o isacontextswitch.strace -s512 python test.py运行此命令将在循环中提供此输出:write(1, "loop\n", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop\n", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop\n", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop\n", 5) = 5
select(0, NULL, NULL, NULL, {0, 500000}) = 0 (Timeout)
write(1, "loop\n", 5)
^{}是一个系统调用,所以是的,您正在进行上下文切换(从技术上讲,当您切换到内核空间时实际上不需要上下文切换,但是如果您有其他进程正在运行,那么您在这里要说的是,除非您已经准备好读取文件描述符上的数据,其他进程可以运行到内核中,以便执行此操作。有趣的是,延迟是在stdin上进行选择。这允许python在诸如ctrl+c输入之类的事件上中断您的输入(如果他们愿意的话),而不必等待代码超时——我认为这是非常整洁的。
我应该注意到这同样适用于time.sleep(0),除了传入的时间参数是{0,0}。这种自旋锁对于任何事情都不是很理想,但是非常短的延迟-^{}和^{}提供了等待事件对象的能力。
编辑:因此我查看了linux的具体功能。do_select(fs\select.c)中的实现进行以下检查: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);
换句话说,如果提供了结束时间,并且两个参数都为零(!0=1,在C)中计算为true,然后等待设置为NULL,选择被视为超时。但是,这并不意味着函数返回给您;它会循环您拥有的所有文件描述符并调用cond_resched,从而可能允许另一个进程运行。换句话说,发生什么完全取决于调度程序;如果您的进程与其他进程相比占用了CPU时间,则很可能会发生上下文切换。如果没有,那么您所在的任务(内核do_select函数)可能会一直执行到完成为止。
不过,我要再次重申,对其他进程更好的最好方法通常是使用除自旋锁之外的其他机制。