资讯专栏INFORMATION COLUMN

PHP协程

SolomonXie / 2447人阅读

摘要:协程协程就是用户态的线程要理解是什么是用户态的线程,必然就要先理解什么是内核态的线程。记住,不是协程,而是协程需要借助的特性来实现。

协程
“协程”就是用户态的线程

要理解是什么是“用户态的线程”,必然就要先理解什么是“内核态的线程”。 内核态的线程是由操作系统来进行调度的,在切换线程上下文时,要先保存上一个线程的上下文,然后执行下一个线程,当条件满足时,切换回上一个线程,并恢复上下文。 协程也是如此,只不过,用户态的线程不是由操作系统来调度的,而是由程序员来调度的,是在用户态的 -- 摘自链接描述

关于“用户态线程”,我们用个小例子来加深理解

我们有两个函数 task1,task2,我们来手动调度它们的执行顺序,比如在task1执行一半的时候去执行task2,两个或者多个函数之间交替执行(这就是协程的概念)。

我们来个正常的函数调用方式:


可想而知,以上的输出肯定是:

task1函数 执行第1
task1函数 执行第2
task2函数 执行第1
task2函数 执行第2

但是我想在程序输出task1函数 执行1之后就输出task2函数 执行1怎么办?

这个时候 yield 就派上用场了,PHP里的协程是需要借助 yield 来完成的。记住,yield 不是协程,而是协程需要借助 yield 的特性来实现。

current();
$task2->current();

以上输出:

task1函数 执行1
task2函数 执行1

很好,以上结果达到了我们的预期。但是怎么让函数里的代码往下执行呢?

调用生成器的next方法:

$task1->next();
$task2->next();

最后你将看到的输出结果是两个函数交替执行输出的:

task1函数 执行1
task2函数 执行1
task1函数 执行2
task2函数 执行2
小段总结

以上的代码实现可以抽象出两个概念,任务调度任务就是task函数,调度就是我们怎么去调用这些task函数

调度器和任务生成器

上一个小段总结里有两个概念叫任务调度,我们简单的封装个任务生成器和调度器

// 任务生成器
$createTask = (function () {
    $tasks = [];
    return function ($callback) use (&$tasks) {
        $task = [
            "task" => $callback(),
            "id" => count($tasks) + 1,
        ];
        array_push($tasks, $task);
        return $task;
    };
})();

// 调度器
function schedule($tasks)
{
    $first = [];
    while (!empty($tasks)) {
        $task = array_shift($tasks);
        if (!array_key_exists($task["id"], $first)) {
            $first[$task["id"]] = true;
            $task["task"]->current();
        } else {
            $task["task"]->next();
        }
        if (!$task["task"]->valid()) {
            unset($tasks[$k]);
        } else {
            array_push($tasks, $task);
        }
    }
}

使用

$tasks = [
    $createTask(function () {
        echo "任务1 执行第1次
";
        yield;
        echo "任务1 执行第2次
";
    }),
    $createTask(function () {
        echo "任务2 执行第1次
";
        yield;
        echo "任务2 执行第2次
";
    })
];

schedule($tasks);

输出结果:

任务1 执行第1次
任务2 执行第1次
任务1 执行第2次
任务2 执行第2次

可以从结果看出,调度器已经实现了多个任务之间进行协作。

网络请求
现在有个需求!就是任务在遇到网络请求的时候,我们无需等待网络请求的响应结果,而是遇到网络请求的时候,把这个任务挂起,然后去执行其它任务,等网络请求收到响应结果了再通知我们处理

这时候需要我们用到非阻塞IO调用相关技术,涉及到系统内核层面,想了解可以点击链接描述

在PHP里我们需要安装个扩展eio,大家自行安装

pecl install eio

编码:

$tasks = [
    $createTask(function () {
        echo "任务1 执行第1次
";
        yield;
        echo "任务1 执行第2次
";
    }),
    $createTask(function () {
        echo "任务2 执行第1次
";

        eio_custom(function () {
            return file_get_contents("https://segmentfault.com/");
        }, EIO_PRI_DEFAULT, function ($data, $ret) {
            echo "请求完成
";
        });
        
        yield;

        echo "任务2 执行第2次
";
    })
];

schedule($tasks);

eio_event_loop();

任务2 执行第1次的时候,遇到网络请求,我们把请求任务交给系统内核,然后切换到其它任务去,等请求任务完成后回调我们传入的函数。

输出结果:

任务1 执行第1次
任务2 执行第1次
任务1 执行第2次
任务2 执行第2次
任务2 执行第1次的请求完成

完!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29283.html

相关文章

  • PHP回顾之协程

    摘要:本文先回顾生成器,然后过渡到协程编程。其作用主要体现在三个方面数据生成生产者,通过返回数据数据消费消费者,消费传来的数据实现协程。解决回调地狱的方式主要有两种和协程。重点应当关注控制权转让的时机,以及协程的运作方式。 转载请注明文章出处: https://tlanyan.me/php-review... PHP回顾系列目录 PHP基础 web请求 cookie web响应 sess...

    Java3y 评论0 收藏0
  • PHP 协程:Go + Chan + Defer

    摘要:为语言提供了强大的协程编程模式。提供的协程语法借鉴自,在此向开发组致敬协程可以与很好地互补。并发执行使用创建协程,可以让和两个函数变成并发执行。协程需要拿到请求的结果。 Swoole4为PHP语言提供了强大的CSP协程编程模式。底层提供了3个关键词,可以方便地实现各类功能。 Swoole4提供的PHP协程语法借鉴自Golang,在此向GO开发组致敬 PHP+Swoole协程可以与...

    nidaye 评论0 收藏0
  • Swoole协程之旅-前篇

    摘要:协程完全有用户态程序控制,所以也被成为用户态的线程。目前支持协程的语言有很多,例如等。协程之旅前篇结束,下一篇文章我们将深入分析原生协程部分的实现。 写在最前   Swoole协程经历了几个里程碑,我们需要在前进的道路上不断总结与回顾自己的发展历程,正所谓温故而知新,本系列文章将分为协程之旅前、中、后三篇。 前篇主要介绍协程的概念和Swoole几个版本协程实现的主要方案技术; 中篇主...

    terasum 评论0 收藏0
  • Swoole 4.4 协程抢占式调度器详解

    摘要:抢占式调度我们在今年年初就计划实现的抢占式调度,以满足实现有些场景下的不均衡调度带来的问题。考虑开线程,负责检查当前执行协程执行时间。达到我们的第二个协程主动抢占第一个协程的效果。 前言 Swoole内核团队开设的专栏,会逐渐投入精力写文章介绍Swoole的开发历程,实现原理,应用实践等,大家可以更好的交流,共同学习,建设PHP生态。 协程调度 去年Swoole推出了4.0版本后,完整...

    Bowman_han 评论0 收藏0
  • PHP下的异步尝试二:初识协程

    摘要:如果仅依靠程序自动交出控制的话,那么一些恶意程序将会很容易占用全部时间而不与其他任务共享。多个操作可以在重叠的时间段内进行。 PHP下的异步尝试系列 如果你还不太了解PHP下的生成器,你可以根据下面目录翻阅 PHP下的异步尝试一:初识生成器 PHP下的异步尝试二:初识协程 PHP下的异步尝试三:协程的PHP版thunkify自动执行器 PHP下的异步尝试四:PHP版的Promise ...

    MudOnTire 评论0 收藏0
  • 关于PHP协程与阻塞的思考

    摘要:线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度标准线程是的。以及鸟哥翻译的这篇详细文档我就以他实现的协程多任务调度为基础做一下例子说明并说一下关于我在阻塞方面所做的一些思考。 进程、线程、协程 关于进程、线程、协程,有非常详细和丰富的博客或者学习资源,我不在此做赘述,我大致在此介绍一下这几个东西。 进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系...

    FullStackDeveloper 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<