PHP并行编程探索之三(定时异步)

3 篇文章 0 订阅

       我们或多或少听过异步这个词,这个词在前端javascrtipt编程中很常见,就是对于定时的或ajax请求任务,我们
不用等待,直接执行接下来的代码,直到之前的数据有返回。
我们来看个栗子:

console.log(new Date());
setTimeout(function(){
    console.log(new Date());
    console.log('111')
},5000);
setTimeout(function(){
    console.log(new Date());
    console.log('1114')
},3000);
console.log(new Date());

打印结果:
line:1 Thu Aug 10 2017 20:50:53 GMT+0800 (CST)
line:10 Thu Aug 10 2017 20:50:53 GMT+0800 (CST)
undefined
line:7 Thu Aug 10 2017 20:50:56 GMT+0800 (CST)
line:8 1114
line:3 Thu Aug 10 2017 20:50:58 GMT+0800 (CST)
line:4 111

我们看到第一行和最后一行的语句立马就打印出来了,但是第8行和第4行的结果则是等了5s才出来
很符合我们的预期,一个定时3s 一个定时5s,我们异步执行耗时以时间长的为准。


那么,实际上真是如此么?我们先来看看PHP中是怎么实先定时异步的。

感谢swoole,提供给了我们一个相同的机会实现了与js相同的定时器来实现定时异步:swoole安装教程

我们使用下面的代码:

function microtime_float()
{
	list($usec, $sec) = explode(" ", microtime());
	return ((float)$usec + (float)$sec);
}
function task1(){  
	echo "wait start" . PHP_EOL;  
	echo "wait end" . PHP_EOL;  
	echo microtime_float()."\n";
};  
  
function task2(){  
	echo "Hello " . PHP_EOL; 
	echo "world!" . PHP_EOL; 
	echo microtime_float()."\n";
}  
echo 'runstart:'.microtime_float()."\n";
swoole_timer_after(3000,'task1');
swoole_timer_after(2000,'task2');
echo 'runend:'.microtime_float()."\n";

打印结果:
runstart:1502370089.7314
runend:1502370089.7315

Hello 
world!
1502370091.735
wait start
wait end
1502370092.7305


按实际的秒数计算确实只用了最长的秒数,所以事实正确了么,我们单进程的PHP变多进程同时执行多任务了么,
将上面的代码稍微改下,我们再看个栗子:

function microtime_float()
{
	list($usec, $sec) = explode(" ", microtime());
	return ((float)$usec + (float)$sec);
}
function task1(){  
	echo "wait start" . PHP_EOL;  
	echo "wait end" . PHP_EOL;  
	sleep(3);//3
	echo microtime_float()."\n";
};  
  
function task2(){  
	echo "Hello " . PHP_EOL; 
	echo "world!" . PHP_EOL; 
	sleep(3);//3
	echo microtime_float()."\n";
}  
echo 'runstart:'.microtime_float()."\n";
swoole_timer_after(3000,'task1');
swoole_timer_after(5000,'task2');
echo 'runend:'.microtime_float()."\n";

运行结果:
runstart:1502377883.6311
runend:1502377883.6312

wait start
wait end
1502377889.6352
Hello 
world!
1502377893.6425


我们发现,实际的运行时间不是8s,而是10s
事实上,计算公式也绝非如此,异步的真正核心,在于用户态的调度,实际上始终是一个进程在做事
没有像多进程那样,同时有多个进程帮你分担做事,我们看到的时间重合仅仅是用户态的定时器时间重合
真正做任务的时候,时间无法重合,因为我们至始至终只有一个进程在干活。



那么他的时间其实是:
a. 最小的延时时间    3s 
b. 任务1延时到点了 主线程有没有空 有 3s
c. 任务2到点了  主线程有没有空 没有 继续等待 
d. 等到任务1执行完成 主线程有空 任务2到点 任务2执行 3s


这里有点难理解为什么不是9s,而多出来1s,其实我也有点疑惑,定时器精确到毫秒级别,那么
程序是不是稳稳准准的在第6s结束执行任务2呢,任务2的定时器在5s的时候没有得到响应直接给自己加1s延时,
在第6s的时候,发现程序还没执行完,又给自己加了1s的延时,所以在第7s终于执行了,多了1s,这个解释可能
稍微合理些,swoole官方的定时器矫正没有给出相关的说明,但是提到了tick的矫正 


那么实际上异步,只是执行阻塞任务时,保存用户态,让非阻塞的任务执行完了,再依次执行阻塞的任务,注意是依次,不是同时。

异步的优点就是:避开系统调度,重新生成用户上下文,减少这部分的时间和开销。

注意:swoole的异步io编程只能在cli 模式下执行。














  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值