什么是协程

什么是协程

  • 协程可以理解为纯用户态的线程,其通过协作而不是抢占来进行切换。相对于进程或者线程,协程所有的操作都可以在用户态完成,创建和切换的消耗更低。
  • 协程不是进程或线程,其执行过程类似于子例程,或者说不带返回值的函数调用
  • 一个程序可以包含多个协程,可以对比与一个进程包含多个线程,因此以下对比协程和线程。而多个线程相对独立,有自己上下文,切换受系统的控制

而协程也相对独立,有自己的上下问,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制

多进程执行流程
	代码执行流程 	→ 

	正常执行图 	→  任务1  →  任务2  →  任务3  →  	完成执行,进程退出。

					→ 任务1 \
	多进程执行执行图 	→ 任务2 	  → 完成执行,进程退出
				    → 任务3 /
协程执行流程
	代码执行流程	→ 
	正常执行图	→  任务1  →  任务2  →  任务3  →  	完成执行,进程退出


协程执行图	任务1	 →    协程切换
			  ↓
			任务2	 →    协程切换
			  ↓
			任务3	 →    协程切换
			  ↓
			任务1	 →    协程切换
			  ↓
			任务2	 →    协程切换
			  ↓
			任务3	 →    协程切换
			   \           /
			    \         /
			     \       /
			      \     /
			       \   /
			       	\ /
			       	 ↓
			  完成执行,进程退出

 

协程执行顺序

  • 原生PHP代码
<?php
	function task1(){
	    for ($i=0;$i<=300;$i++){
	        //写入文件,大概要3000微秒
	        usleep(3000);
	        echo "写入文件{$i}\n";
	    }
	}
	function task2(){
	    for ($i=0;$i<=500;$i++){
	        //发送邮件给500名会员,大概3000微秒
	        usleep(3000);
	        echo "发送邮件{$i}\n";
	    }
	}
	function task3(){
	    for ($i=0;$i<=100;$i++){
	        //模拟插入100条数据,大概3000微秒
	        usleep(3000);
	        echo "插入数据{$i}\n";
	    }
	}
	task1();
	task2();
	task3();
?>

 

  • 下面这段代码也是做了3件事,写入文件、发送邮件、及插入数据。但是和上面的不同的是,这段代码将这3件事交叉执行,每个任务执行完一次之后,切换到另一个任务,如此循环。类似于这样的执行顺序,就是协程。
<?php
	function task1($i)
	{
	    //使用$i标识 写入文件,大概要3000微秒
	    if ($i > 300) {
	        return false;//超过300不用写了
	    }
	    echo "写入文件{$i}\n";
	    usleep(3000);
	    return true;
	}

	function task2($i)
	{
	    //使用$i标识 发送邮件,大概要3000微秒
	    if ($i > 500) {
	        return false;//超过500不用发送了
	    }
	    echo "发送邮件{$i}\n";
	    usleep(3000);
	    return true;
	}

	function task3($i)
	{
	    //使用$i标识 插入数据,大概要3000微秒
	    if ($i > 100) {
	        return false;//超过100不用插入
	    }
	    echo "插入数据{$i}\n";
	    usleep(3000);
	    return true;
	}

	$i           = 0;
	$task1Result = true;
	$task2Result = true;
	$task3Result = true;
	while (true) {
	    $task1Result && $task1Result = task1($i);
	    $task2Result && $task2Result = task2($i);
	    $task3Result && $task3Result = task3($i);
	    if($task1Result === false && $task2Result === false && $task3Result === false){
	        break;//全部任务完成,退出循环
	    }
	    $i++;
	}
?>

协程是一种用代码实现任务交叉执行的逻辑,协程可以使得代码1中的3个函数交叉运行,在实现了协程的一种框架中,我们不需要通过代码2的方法实现任务交叉运行。直接可让代码1中的while(1),执行一次后切换。

 

协程的实现

 在php中,实现协程主要采用两种方式

  1. yield生成器实现(详细原理可查看http://www.php20.cn/article/148)
  2. swoole扩展实现
  • swoole实现协程代码
<?php
	function task1(){
	    for ($i=0;$i<=300;$i++){
	        //写入文件,大概要3000微秒
	        usleep(3000);
	        echo "写入文件{$i}\n";
	        Co::sleep(0.001);//挂起当前协程,0.001秒后恢复//相当于切换协程
	    }
	}
	function task2(){
	    for ($i=0;$i<=500;$i++){
	        //发送邮件给500名会员,大概3000微秒
	        usleep(3000);
	        echo "发送邮件{$i}\n";
	        Co::sleep(0.001);//挂起当前协程,0.001秒后恢复//相当于切换协程
	    }
	}
	function task3(){
	    for ($i=0;$i<=100;$i++){
	        //模拟插入100条数据,大概3000微秒
	        usleep(3000);
	        echo "插入数据{$i}\n";
	        Co::sleep(0.001);//挂起当前协程,0.001秒后恢复//相当于切换协程
	    }
	}
	$pid1 = go('task1');//go函数是swoole的开启协程函数,用于开启一个协程
	$pid2 = go('task2');
	$pid3 = go('task3');
?>

以上代码,即可实现切换函数。

 

协程与进程

由上面的协程执行顺序中的代码2,我们很容易发现,协程其实只是运行在一个进程中的函数,只是这个函数会被切换到下一个执行,可以这么说:
        协程只是一串运行在进程中的任务代码,只是这些任务代码可以交叉运行。 注意,协程并不是多任务并行,属于多任务串行,每个进程在一个时间只执行了一个任务。

 

协程注意事项

变量使用

  • 在协程中,需要特别注意,不要使用$_GET,$_POST,$GLOBAL等超全局变量,尤其是需要修改变量值并读取时,将造成协程间变量数据错乱
  • 协程中访问外部变量必须使用use关键字,或者传形参方式,不能引用变量。
  • 如果要做多协程之间的通信,可以使用channel方式通信。

扩展冲突

  • 与xdebug、xhprof、balckfire等zend扩展不兼容,例如不能使用xhprof对协程Server进行性能分析采样

 

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值