php的libev扩展

pecl上新添了一个ev扩展,目前版本是0.2.0,已经stable。这个扩展为php提供了libev库的接口。

ev is a PECL extension providing inteface to libev library – high performance full-featured event loop written in C.

ABOUT LIBEV Libev is an event loop: you register interest in certain events (such as a file descriptor being readable or a timeout occurring), and it will manage these event sources and provide your program with events.

那么什么是libev呢,从网上摘录一段:

libev 是高性能事件循环/事件模型的网络库,并且包含大量新特性。 它是继lievent和Event perl module之后的一套全新网络库。它追求的目标:速度更快,bug更少,特性更多,体积更小。 它和libevent很像,按照作者的介绍,可以作为libevent的替代者,能够提供更高的性能。并不需要复杂的配置。

看起来和之前提到的libevent大有渊源,但是这个扩展的作者显然比较活跃,一周内提交了3个版本。

代码示例

timer的使用

<?php
// 创建一个timer并于2秒后触发
$w1 = new EvTimer(2, 0, function () {
    echo \"2 seconds elapsedn\";
});

// 创建一个timer并于2秒后触发,每秒重复
// 直到我们手工停止
$w2 = new EvTimer(2, 1, function ($w) {
    echo \"is called every second, is launched after 2 secondsn\";
    echo \"iteration = \", Ev::iteration(), PHP_EOL;

    // Stop the watcher after 5 iterations
    Ev::iteration() == 5 and $w->stop();
    // Stop the watcher if further calls cause more than 10 iterations
    Ev::iteration() >= 10 and $w->stop();
});

// 创建一个已停止的timer,手工start才有效
$w_stopped = EvTimer::createStopped(10, 5, function($w) {
    echo \"Callback of a timer created as stoppedn\";

    // Stop the watcher after 2 iterations
    Ev::iteration() >= 2 and $w->stop();
});

// Loop until Ev::stop() is called or all of watchers stop
Ev::run();

// Start and look if it works
$w_stopped->start();
echo \"Run single iterationn\";
Ev::run(Ev::RUN_ONCE);

echo \"Restart the second watcher and try to handle the same events, but don't blockn\";
$w2->again();
Ev::run(Ev::RUN_NOWAIT);

$w = new EvTimer(10, 0, function() {});
echo \"Running a blocking loopn\";
Ev::run();
echo \"ENDn\";
?>

输出内容

2 seconds elapsed
is called every second, is launched after 2 seconds
iteration = 1
is called every second, is launched after 2 seconds
iteration = 2
is called every second, is launched after 2 seconds
iteration = 3
is called every second, is launched after 2 seconds
iteration = 4
is called every second, is launched after 2 seconds
iteration = 5
Run single iteration
Callback of a timer created as stopped
Restart the second watcher and try to handle the same events, but don't block
Running a blocking loop
is called every second, is launched after 2 seconds
iteration = 8
is called every second, is launched after 2 seconds
iteration = 9
is called every second, is launched after 2 seconds
iteration = 10
END

I/O事件

例1

<?php
// Wait until STDIN is readable
$w = new EvIo(STDIN, Ev::READ, function ($watcher, $revents) {
    echo \"STDIN is readablen\";
});
Ev::run(Ev::RUN_ONCE);
?>

例2

<?php
/* Use some async I/O to access a socket */

// `sockets' extension still logs warnings
// for EINPROGRESS, EAGAIN/EWOULDBLOCK etc.
error_reporting(E_ERROR);

$e_nonblocking = array (/*EAGAIN or EWOULDBLOCK*/11, /*EINPROGRESS*/115);

// Get the port for the WWW service
$service_port = getservbyname('www', 'tcp');

// Get the IP address for the target host
$address = gethostbyname('google.co.uk');

// Create a TCP/IP socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === FALSE) {
    echo \"socket_create() failed: reason: \"
        .socket_strerror(socket_last_error()) . \"n\";
}

// Set O_NONBLOCK flag
socket_set_nonblock($socket);

// Abort on timeout
$timeout_watcher = new EvTimer(10.0, 0., function () use ($socket) {
    socket_close($socket);
    Ev::stop(Ev::BREAK_ALL);
});

// Make HEAD request when the socket is writable
$write_watcher = new EvIo($socket, Ev::WRITE, function ($w)
    use ($socket, $timeout_watcher, $e_nonblocking) {
    // Stop timeout watcher
    $timeout_watcher->stop();
    // Stop write watcher
    $w->stop();

    $in = \"HEAD / HTTP/1.1rn\";
    $in .= \"Host: google.co.ukrn\";
    $in .= \"Connection: Closernrn\";

    if (!socket_write($socket, $in, strlen($in))) {
        trigger_error(\"Failed writing $in to socket\", E_USER_ERROR);
    }

    $read_watcher = new EvIo($socket, Ev::READ, function ($w, $re)
        use ($socket, $e_nonblocking) {
        // Socket is readable. recv() 20 bytes using non-blocking mode
        $ret = socket_recv($socket, $out, 20, MSG_DONTWAIT);

        if ($ret) {
            echo $out;
        } elseif ($ret === 0) {
            // All read
            $w->stop();
            socket_close($socket);
            return;
        }

        // Caught EINPROGRESS, EAGAIN, or EWOULDBLOCK
        if (in_array(socket_last_error(), $e_nonblocking)) {
            return;
        }

        $w->stop();
        socket_close($socket);
    });

    Ev::run();
});

$result = socket_connect($socket, $address, $service_port);

Ev::run();
?>

输出

HTTP/1.1 301 Moved Permanently
Location: http://www.google.co.uk/
Content-Type: text/html; charset=UTF-8
Date: Sun, 23 Dec 2012 16:08:27 GMT
Expires: Tue, 22 Jan 2013 16:08:27 GMT
Cache-Control: public, max-age=2592000
Server: gws
Content-Length: 221
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Connection: close

源码

源码放在bitbucket

作者: 发表于January 1, 2013 at 6:28 pm

版权信息: 可以任意转载, 转载时请务必以超链接形式标明文章原始出处作者信息及此声明

Tags: ,,

7 条评论 »

  1. paul 于 2013-01-06 @ 16:55:50 留言

    大哥,我想用bbpress做一个论坛,希望能得到您的指点。
    我的QQ:337109563

  2. bluebirdhsz 于 2013-01-23 @ 16:53:28 留言

    如果能用 libev和libeio结合做一个扩展就好了..那就是 node.js 了

  3. Volcano 于 2013-01-23 @ 17:40:47 留言

    虽然没有扩展,但是有一个类库可以做类似的事情 http://reactphp.org/

  4. bluebirdhsz 于 2013-01-29 @ 10:54:21 留言

    你好,非常感谢你的回复。
    我最近在某个问题上比较搞不清楚,也没有查到更详细的说明,所以只能在这里请教你一下。

    关于 HashPosition 我不太明白它的用处,还有对数组的操作系列函数如: zend_hash_get_current_key_ex, zend_hash_internal_pointer_reset_ex, zend_hash_get_current_data_ex,它还有 不带后面_ex的函数: zend_hash_get_current_key, zend_hash_internal_pointer_reset, zend_hash_get_current_data,后面的ex大概都是需要传一个HashPosition进去,不解,希望你能指点一二。

  5. Volcano 于 2013-01-29 @ 11:00:42 留言

    对不起,c我不擅长,帮不上你

  6. bluebirdhsz 于 2013-01-29 @ 11:02:32 留言

    好吧,谢谢您及时回复。我会常来看看的。

  7. dryangkun 于 2013-05-24 @ 14:04:55 留言

    @bluebirdhsz,HashPosition这个结构是用来保存当前key在数组的位置(第几个)

RSS 为此帖反馈评论

留条评论