关于Web编程异步模型的白日梦

早上刷牙,处于半睡状态。突然想起昨天晚上看到的那个 go-lang 的 MVC 框架,若使用 go func() 方式异步获取数据,应当是不错的。窃喜……梦醒……

在地铁上被前前后后那些特种男女逼到车角,无奈。又想起早上那个白日梦,遂上网搜索了一番。得老赵的佳作一篇《F# 与ASP.NET(1):基于事件的异步模式与异步Action》。之前看过,由于对微软无爱,未能细品。今日一读,如醍醐灌顶,豁然开朗。

遂整理思路如下,以待后用。

在说异步模型之前,先说说最常见的同步模型吧。例如下面的 PHP 代码:

// 获取数据
$userInfo = getUserInfo();
$newsList = getNewsList();
$topRateNewsList = getNewsList('DESC `rate`');
// 创建模板,绑定变量
$tmp = CreateTemplate();
$tmp->bind('userInfo', $userInfo);
$tmp->bind('newsList', $newsList);
$tmp->bind('topRateNewsList', $topRateNewsList);
// 渲染模板,输出
$tmp->render();
echo $tmp;

在这段代码中,所有调用都是顺序的。也就是说,如果 getUserInfo($userId) 没有返回用户信息的话,getNewsList(5) 永远都不会被调用。实际情况,可能是用户信息是从用户库取数据,新闻是从新闻库取数据。假设新闻库运行良好,而由于某种原因用户库宕机了,那么这次请求也就废掉了。故障也从一个库的宕机扩散到整个站点。

现在,我白日做梦的创建一种新语言 go-php,引入 go-lang 的关键字 go 到 php 中:

// 创建一个数据通道
$chan = CreateChan();
// 获取数据,并放到数据通道上去
go getUserInfo($chan);
go getNewsList($chan);
$params = array('DESC `rate`');
go getNewsList($chan, $params);
// 创建模板
$tmp = CreateTemplate();
// 从通道上取数据
while($d = $chan->read()) {
    if ($d['error']) {
        // 数据有错误 ……处理一下吧
    } else {
        $tmp->bind($d['key'], $d['data']);
    }
}
// 渲染模板,输出
$tmp->render();
echo $tmp;

好了,这其实不是什么新奇创造,这只是一个二段式异步调用(Begin/End)。这有点像大宗采购,采购商并不一件一件的商品进行采购,而是拿着清单说:“好了,兄弟,这是我要的货,你们帮我找齐,放到码头406号仓库去……”,然后他就在 406 号仓库等着点货了。这段代码还可以改进,就像采购清单一样,将这个清单推到数据层,数据层把数据返回到数据通道上去。恩,应该不少人在自己的应用中使用 MQ,Memcache 甚至 pipe 实现了这种异步了吧。

再来看另外一段 go-php 代码:

/**
 * 回调函数
 * @param $tmp 模板
 * @param $d 返回的数据
 */
function callbackBind($tmp, $d) {
    if ($d['error']) {
        // 数据有错误 ……处理一下吧
    } else {
        $tmp->bind($d['key'], $d['data']);
    }
}
// 创建模板
$tmp = CreateTemplate();
// 获取数据,并设置数据回调
go getUserInfo(callbackBind, $tmp);
go getNewsList(callbackBind, $tmp);
$params = array('DESC `rate`');
go getNewsList(callbackBind, $tmp, $params);
// 如果不是所有数据都回调了,则阻塞
$tmp->wait();
// 渲染模板,输出
$tmp->render();
echo $tmp;

这就是老赵的事件回调的异步处理的 go-php 版本。这有点像渠道商订货(或者淘宝上的无货代理?):“我需要XXXX,你帮我送到XXXX去”。然后坐等,所有的内容都送到了,就收钱走人。

对于数据读取的错误,只要处理得当也不是致命的。最多在渲染页面的时候,少某块数据,用户只会奇怪:“这次怎么打开没有新闻那部分的内容了呢……刷新一下看看……”。而不会说:“烂网站,又打不开了……”用户体验直线上升啊!

好了,梦就做到这里。相信这两种方式其实已经有实际案例了。我比较孤陋寡闻一些,了解的不多。而且有的东西,未经许可也不好多说……大家私下打听吧。

总之呢,两种异步模型各自有各自的好处。并行的数据存取,提高 I/O 利用率是其本质。王道啊……

Join the Conversation

4 Comments

  1. 构想不错,实现了吗?如果并发量大,某个请求时间太长,会导致php进程堵塞,进而导致Nginx 504。已经屡屡遇到这样的问题了。仍未有好的解决方案,望赐教。

Leave a comment

Your email address will not be published. Required fields are marked *