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

本文探讨了JavaScript中的异步执行概念,通过示例展示了setTimeout如何工作,并对比了PHP中使用swoole实现的异步定时器。尽管在PHP中可以模拟异步行为,但实际仍然是单进程执行,不存在并发。异步的核心在于用户态调度,避免系统调用,减少开销。swoole的异步IO编程需在CLI模式下运行。
摘要由CSDN通过智能技术生成

我们或多或少听过异步这个词,这个词在前端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,我们异步执行耗时以时间长的为准。

0818b9ca8b590ca3270a3433284dd417.png

那么,实际上真是如此么?我们先来看看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

事实上,计算公式也绝非如此,异步的真正核心,在于用户态的调度,实际上始终是一个进程在做事,

没有像多进程那样,同时有多个进程帮你分担做事,我们看到的时间重合仅仅是用户态的定时器时间重合

真正做任务的时候,时间无法重合,因为我们至始至终只有一个进程在干活。

0818b9ca8b590ca3270a3433284dd417.png

那么他的时间其实是:

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模式下执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值