在一个项目中使用php调用pcntl模块实现多进程并发队列任务并通过jquery异步获取后台执行结果,但是在前台ajax轮询后台结果的时候出现阻塞,如图所示:
第一个请求是用来启动后台多任务进程deamon的ajax请求,这个请求由于调用pcntl派生子进程执行任务,故这个ajax请求会长时间处于等待响应的状态,后面的请求是每隔400毫秒请求一次后台查找结果。如图一所示,第一个请求发送后,后面的请求一直处于阻塞状态,导致setInterval轮询的请求全部被hold住。当第一个请求任务全部执行完毕后,后面的请求基本在统一时刻去后台拉取结果,这个时候每个请求返回的结果是一摸一样的,也就是说轮询已经不存在实际意义。
在网上找了一些说法,肯定了jQuery是具有非常强大异步并发处理能力,同时也排除了浏览器导致阻塞的可能。从一些文章中找到一种说法是有可能session在使用session file的时候会lock住,导致多个请求会等待第一个请求结束使session file释放,并给出了使用session_write_close函数解决锁文件的问题。
PHP官方文档是有如下解释:
End the current session and store session data.
Session data is usually stored after your script terminated without the need to call session_write_close(), but as session data is locked to prevent concurrent writes only one script may operate on a session at any time. When using framesets together with sessions you will experience the frames loading one by one due to this locking. You can reduce the time needed to load all the frames by ending the session as soon as all changes to session variables are done.
在请求的队列逻辑前面加上session_write_close()函数,将session立即写入session file,释放文件,而不是php script执行完毕再写入file,再释放,这样可以避免file长时间锁住,而导致后面请求的逻辑不能读取session file。
改造后的效果非常明显,轮询结果恢复正常: