{"id":99,"date":"2022-01-12T00:07:48","date_gmt":"2022-01-11T15:07:48","guid":{"rendered":"https:\/\/www.b64.pw\/blog\/?p=99"},"modified":"2022-01-12T00:07:48","modified_gmt":"2022-01-11T15:07:48","slug":"php8-1%e3%81%ae%e6%96%b0%e6%a9%9f%e8%83%bd%e7%b4%b9%e4%bb%8b-fibers","status":"publish","type":"post","link":"https:\/\/www.b64.pw\/blog\/?p=99","title":{"rendered":"PHP8.1\u306e\u65b0\u6a5f\u80fd\u7d39\u4ecb Fibers"},"content":{"rendered":"\n<p>\u4e26\u884c\u51e6\u7406\u3092\u66f8\u304d\u3084\u3059\u304f\u3059\u308b\u6a5f\u69cb\u3002<br>\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306b\u3088\u308b\u3068<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\"><p>Libraries will generally build further abstractions around Fibers, so there&#8217;s no need to interact with them directly.<\/p><cite>https:\/\/www.php.net\/releases\/8.1\/en.php#fibers<\/cite><\/blockquote>\n\n\n\n<p>\u3068\u66f8\u304b\u308c\u3066\u3044\u3066\u3001\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u4f5c\u308b\u4eba\u4ee5\u5916\u306f\u76f4\u63a5\u4f7f\u3046\u3053\u3068\u306f\u306a\u3044\u3068\u306e\u3053\u3068\u3002<br>(\u9006\u306b\u8a00\u3048\u3070Coroutine\u3084Promise\u3092\u4f7f\u3046\u3088\u3046\u306a\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u4f5c\u308b\u4eba\u306f\u4f7f\u3046\u6a5f\u4f1a\u3042\u308a\u305d\u3046)<\/p>\n\n\n\n<p>Fibers\u3092\u4f7f\u3063\u3066Listen\u3059\u308b\u3068\u306a\u308b\u3068\u6b21\u306e\u3088\u3046\u306a\u30b3\u30fc\u30c9\u306b\u306a\u308b\u304b\u306a\u3068\u601d\u308f\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;?php\r\n\r\n$address = '0.0.0.0';\r\n$port = 3080;\r\nif (($sock = stream_socket_server(\"tcp:\/\/{$address}:{$port}\", $errno, $errstr)) === false) {\r\n    echo \"stream_socket_server() failed: reason: {$errstr} {$errno}\" . PHP_EOL;\r\n    exit(255);\r\n}\r\n\r\r\r\ndefine('QUIT_MSG', 'QUIT');\r\nclass socket_manager{\r\n    public static $connections = 0; \r\n    static function create_fiber($conn){\r\n        stream_set_blocking($conn, false);\r\n        $fiber = new Fiber(function () use ($conn): void {\r\n            while(true){\r\n                $resume_msg = Fiber::suspend('fiber');\/\/ resume()\u5f8c\u3053\u306e\u6b21\u306e\u884c\u304b\u3089\u5b9f\u884c\u3055\u308c\u308b\r\n                echo \"Value used to resume fiber: \", $resume_msg, PHP_EOL;\r\n                if($resume_msg === QUIT_MSG){\r\n                    disconnect_client($conn);\r\n                    return;\r\n                }\r\n                $tmp_conn_list = &#91;$conn];\r\n                $write_conn = null;\r\n                $expect = null;\r\n                $is_recv = stream_select($tmp_conn_list, $write_conn, $expect, 0, 0);\r\n                if($is_recv === false){\r\n                    echo 'stream_select error'.PHP_EOL;\r\n                    disconnect_client($conn);\r\n                    return;\r\n                }\r\n                $recv = stream_get_contents($conn);\r\n                if($recv === false ){\r\n                    echo 'stream_get_contents error'.PHP_EOL;\r\n                    return;\r\n                }\r\n                \/*if($recv === ''){\r\n                    echo 'no data'.PHP_EOL;\r\n                    continue;\r\n                }*\/\r\n                echo \"received {$recv}\".PHP_EOL;\r\n                $res = fwrite($conn, $recv.\"\\r\\n\");\/\/ echo response\r\n                if($res === false){\r\n                    static::disconnect_client($conn);\r\n                    return;\r\n                }\r\n            }\r\n        });\r\n\r\n        $value = $fiber->start();\r\n        echo \"Value from fiber suspending: \", $value, PHP_EOL;\r\n        return $fiber;\r\n    }\r\n    static function disconnect_client($conn){\r\n        fclose($conn);\r\n        echo \"$conn disconnected.\".PHP_EOL;\r\n    }\r\n}\r\n\r\nwhile(true){\r\n    if (($conn = stream_socket_accept($sock)) === false) {\r\n        socket_close($sock);\r\n        exit(255);\r\n    }\r\n    echo \"connected. current connections: {socket_manager::$connections}\".PHP_EOL;\r\n    $fiber = socket_manager::create_fiber($conn);\r\n\r\n    while(true){\r\n        usleep(200000);\/\/ 200ms\u3054\u3068\u306bfiber\u3092resume\u3059\u308b\r\n        echo 'main loop start'.PHP_EOL;\r\n        if(!$fiber->isSuspended()){\r\n            break;\r\n        }\r\n        $fiber->resume(date('Y-m-d\\TH:i:s\\Z'));\/\/ Fiber::suspend()\u3057\u305f\u6b21\u306e\u884c\u304b\u3089\u5b9f\u884c\r\n    }\r\n    echo 'main loop end'.PHP_EOL;\r\n    unset($fiber);\r\n}\r\nsocket_close($sock);<\/code><\/pre>\n\n\n\n<p>Fibers\u3068\u3044\u3048\u3069\u3082\u4e0b\u8a18\u306e\u56f3\u306e\u3088\u3046\u306b\u30b7\u30f3\u30b0\u30eb\u30b9\u30ec\u30c3\u30c9\u306a\u306e\u3067\u3042\u307e\u308a\u5b9f\u7528\u7684\u3067\u306f\u306a\u3044\u3067\u3059\u304c\u3001thread\u3084fork\u3068\u7d44\u307f\u5408\u308f\u305b\u308c\u3070\u4f7f\u3044\u3069\u3053\u308d\u304c\u3042\u308a\u305d\u3046\u3067\u3059\u3002<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img src=\"https:\/\/wiki.php.net\/lib\/exe\/fetch.php?w=800&amp;tok=4bc982&amp;media=https%3A%2F%2Fwiki.php.net%2F_media%2Frfc%2Ffiber-flow.png\" alt=\"Fiber execution flow\"\/><figcaption>c.f. https:\/\/wiki.php.net\/rfc\/fibers<\/figcaption><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\u4e26\u884c\u51e6\u7406\u3092\u66f8\u304d\u3084\u3059\u304f\u3059\u308b\u6a5f\u69cb\u3002\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306b\u3088\u308b\u3068 Libr &#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=\/wp\/v2\/posts\/99"}],"collection":[{"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=99"}],"version-history":[{"count":1,"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=\/wp\/v2\/posts\/99\/revisions"}],"predecessor-version":[{"id":100,"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=\/wp\/v2\/posts\/99\/revisions\/100"}],"wp:attachment":[{"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=99"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=99"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.b64.pw\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=99"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}