源码分析python sleep函数实现原理

最近在重读《UNIX环境高级编程》,在想linux下sleep()函数是如何实现的,他的原理是啥? 跟python time.sleep()是否一样.

首先看看linux sleep()的函数是怎么个实现方法,感觉实现起来有些下小麻烦呀. 

该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。http://xiaorui.cc/?p=3160

sleep()的实现分为三步:

1.注册一个信号signal(SIGALRM,handler)。接收内核给出的一个信号。如果不主动针对sigalrm信号处理,那么就会关闭进程的。 

2.调用alarm()函数。

3.pause()挂起进程, 当你的sigalrm信号来的时候,处理信号对应函数,然后继续往下走.

具体代码实现:

#xiaorui.cc
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

///时钟编程 alarm()

void wakeUp()
{
      printf("please wakeup!!/n");
}

int main(void) {
     printf("sleep! 1s /n");
     signal(SIGALRM,wakeUp);
     alarm(1);
     pause();
     printf("end/n");
    return EXIT_SUCCESS;
}

然后再strace下看看sleep()函数都干了些什么.
使用alarm函数可以设置一个计时器,在将来某个指定的时间,该计时器会超时。当计时器超时时,产生SIGALRM信号。如果不忽略或不捕捉此信号,则其默认动作是终止调用该alarm函数的进程。 pause函数使调用进程挂起直至捕捉到一个信号。

rt_sigaction(SIGALRM, {0x400594, [ALRM], SA_RESTORER|SA_RESTART, 0x3b520326a0}, {SIG_DFL, [], 0}, 8) = 0
alarm(1)                                = 0
pause()                                 = ? ERESTARTNOHAND (To be restarted)
--- SIGALRM (Alarm clock) @ 0 (0) ---
rt_sigreturn(0)                         = -1 EINTR (Interrupted system call)
write(1, "sleep! 1s /nplease wakeup!!/nend"..., 34sleep! 1s /nplease wakeup!!/nend/n) = 34
exit_group(0)                           = ?

那我们再来看看python怎么一回事. 用strace测试下面的python小脚本.

import time
print “start”
time.sleep(1)
print “end”

通过下面的strace结果已经相当的明了, 直接借助于select io多路复用模型来实现的,select一般是用来监控文件描述符变化的. 

write(1, “start\n”, 6start
)                  = 6
select(0, NULL, NULL, NULL, {1, 0}

)     = 0 (Timeout)
write(1, “end\n”, 4end
)                    = 4
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x3df860f710}, {0x35b31033f0, [], SA_RESTORER, 0x3df860f710}, 8) = 0
exit_group(0)

再来验证下在python是不是可以直接调用select来实现sleep

In [1]: import select

In [2]: select.select([], [], [], 1)
Out[2]: ([], [], [])

在python的modules是看不到time的相关源码,在你编译python的时候,time模块已经被编程成so文件。

下面是python的timemodule.c源码
https://hg.python.org/cpython/file/3ae2cd85a908/Modules/timemodule.c

#xiaorui.cc
floatsleep(double secs)
{
/* XXX Should test for MS_WINDOWS first! */
#if defined(HAVE_SELECT) && !defined(__EMX__)
    struct timeval t;
    double frac;
    int err;

    frac = fmod(secs, 1.0);
    secs = floor(secs);
    t.tv_sec = (long)secs;
    t.tv_usec = (long)(frac*1000000.0);
    Py_BEGIN_ALLOW_THREADS
    err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
    Py_END_ALLOW_THREADS
    ... ... 省略

下面是select函数的具体定义.

#xiaorui.cc
select.select(rlist, wlist, xlist[, timeout])
This is a straightforward interface to the Unix select() system call. The first three arguments are sequences of ‘waitable objects’: either integers representing file descriptors or objects with a parameterless method named fileno() returning such an integer:

rlist: wait until ready for reading
wlist: wait until ready for writing
xlist: wait for an “exceptional condition” (see the manual page for what your system considers such a condition)

虽然简单说了 pyhton及c语言的sleep的实现,但这也只是语言层面的实现.   还是没有详细到系统内核方面的,看来还是需要更深层次的学习。 

END.


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

2 Responses

发表评论

邮箱地址不会被公开。 必填项已用*标注