V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
szopen
V2EX  ›  PHP

和 JS 一样的 php setTimeout 函数

  •  
  •   szopen · 2016-07-08 16:36:54 +08:00 · 3992 次点击
    这是一个创建于 3050 天前的主题,其中的信息可能已经有所发展或是发生改变。
    技术依赖

    需要 PHP 5.5 以上,支持生成器
    需要支持 ticks


    实现代码见
    http://toknot.com/blog/php-setTimeout.html

    主要利用生成器实现,和 js 的一样,不会阻塞脚本执行(不同于 sleep 的阻塞)
    回调函数一定会在延迟时间执行。延迟时间单位是毫秒,千分之一秒
    11 条回复    2016-07-11 21:34:11 +08:00
    laoyuan
        1
    laoyuan  
       2016-07-08 17:39:47 +08:00
    PHP7 跑通了,确实非阻塞。
    5.5.34 这一行
    function setTimeout(callable $callback, int $time) : Generator{
    报错
    PHP Parse error: parse error, expecting `'{''
    qa2080639
        2
    qa2080639  
       2016-07-08 19:07:13 +08:00
    @laoyuan 5.5.12 +1
    shyling
        3
    shyling  
       2016-07-08 19:22:42 +08:00
    咦,我不认识的 php 。马克
    Balthild
        4
    Balthild  
       2016-07-09 01:49:58 +08:00 via Android
    Tick 函数啊,有意思。
    这个东西文档很少,也几乎没见到过人用,据说性能不好…
    dawniii
        5
    dawniii  
       2016-07-09 07:54:38 +08:00
    declare 据说不应该是过时的吗?每走一行代码就去检测任务。效率很低。
    这段代码的原理就是每走一行代码就去检测是否有定时任务。。。
    最后再加上 register_shutdown_function 这个函数。等脚本结束了,执行这个函数继续检测任务。
    可以去看看 workerman 的定时器实现。
    jhdxr
        6
    jhdxr  
       2016-07-09 14:38:20 +08:00
    @dawniii declare 没过时,过时的只是它的一种用法,也就是 @Balthild 说的 tick ,效率的确很低。
    workerman 的 timer 实现的方式也类似。用的是 pcntl 库的函数,每秒给自己发一个 alarm ,去检查下有没有要执行的东西,效率也不高_(:з」∠)_
    其实 php 自己没有 ** 原生很好 ** 的支持多线程,想要高效的去实现这种异步的东西不大可能_(:з」∠)_ 还是上扩展吧,比如 swoole 。。。
    jhdxr
        7
    jhdxr  
       2016-07-09 14:38:55 +08:00
    @laoyuan 因为 LZ 用了一个 7 的语法,返回值类型声明,` : Generator`去掉即可
    dawniii
        8
    dawniii  
       2016-07-09 19:03:00 +08:00
    @jhdxr 感谢 明白了。但是我看 workerman 的定时器好像是有两个流程 一个是在没有注册 event 的时候走信号,另一个是走 event (我记得 workerman 启动过程会注册 event, select 或者 libevent )。如果是这样效率应该是可以的。还有就是 LZ 代码我试着改了改,不用 yield 就能实现。。。
    szopen
        9
    szopen  
    OP
       2016-07-11 14:40:02 +08:00
    @dawniii 的确可以不用 yield 。另外 tick 效率的确十分低下,据分析,当启用 tick 后, PHP 会在 所有 opcode 后插入 TICK 的 opcode,
    PHP 7.1 的 Asynchronous Signal Handling 或许会解决 pcntl 信号的效率问题 https://wiki.php.net/rfc/async_signals
    szopen
        10
    szopen  
    OP
       2016-07-11 14:55:36 +08:00
    @dawniii 如果不用 yield ,可能会加重 tick hander 函数的复杂度, setTimeout 函数实现也会变得复杂起来
    dawniii
        11
    dawniii  
       2016-07-11 21:34:11 +08:00
    @szopen 貌似没有复杂啊

    <?php
    //enable ticks
    declare (ticks = 1);

    //setTimeout event list
    $timeoutQueue = new SplObjectStorage;

    register_tick_function(function() {
    global $timeoutQueue;
    foreach ($timeoutQueue as $v) {
    $callBack = $v();
    if (is_callable($callBack)) {
    $callBack();
    $timeoutQueue->detach($v);
    }
    }
    });

    register_shutdown_function(function() {
    global $timeoutQueue;
    while($timeoutQueue->count()) {
    foreach ($timeoutQueue as $v) {
    $callBack = $v();
    if (is_callable($callBack)) {
    $callBack();
    $timeoutQueue->detach($v);
    }
    }
    usleep(1000);
    }
    });

    function setTimeOut($callback, $time)
    {
    global $timeoutQueue;
    $end = microtime(true) * 1000 + $time;

    $f = function() use ($callback,$end) {
    if (microtime(true)*1000 >= $end) {
    return $callback;
    } else {
    return false;
    }
    };
    $timeoutQueue->attach($f);
    return $f;
    }

    function clearTimeout(Closure $f) {
    global $timeoutQueue;
    $timeoutQueue->detach($f);
    }

    setTimeOut(function() {
    echo 'aaaa';
    },3000);
    setTimeOut(function() {
    echo 'bbbb';
    },6000);
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5869 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 02:57 · PVG 10:57 · LAX 18:57 · JFK 21:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.