PHP,暂停脚本执行,直到另一个正在运行的脚本发出事件信号?
Posted
技术标签:
【中文标题】PHP,暂停脚本执行,直到另一个正在运行的脚本发出事件信号?【英文标题】:PHP, Pause script execution until an event is signaled by another running script? 【发布时间】:2011-02-04 03:16:14 【问题描述】:我希望一个 php 脚本等待另一个脚本执行期间发送的事件。
用户 A 和用户 B 都是我网站的访问者。当用户 A 访问 index.php 时,页面开始执行,但直到用户 B 也访问 index.php 才返回。 (该页面仅在两个用户都连接到 Web 服务器时显示,例如:就像两个守卫通过同时转动钥匙打开保险箱。)
实现这一点的一种方法是让 index.php 暂停其执行,直到收到由其他用户访问 index.php 引起的通知。
为此,我查看了
-
libevent;但它似乎不允许在信令期间发送“ID”或“字符串”。
来自梨的Event_Dispatcher;但它在“脚本之间”不起作用。
PHP 共享内存函数;但似乎不能等到内存改变。
【问题讨论】:
【参考方案1】:您可能不希望 PHP 脚本完全暂停。用户会坐在那里以为页面冻结了。相反,我会使用 AJAX 将 USER-A 的状态保存在数据库中,然后使用 AJAX 再次检查 USER-B 是否也保存了他们的状态。想法是让 AJAX 在后台默默地检查 USER-B 的状态。当它检测到登录时,让您的回调函数对页面进行处理!
【讨论】:
感谢您的回复;但是我不能使用 AJAX。这里有更多细节。用户是 C 客户端程序,不介意等待。我需要闪电般的速度,而 ajax 的返回速度不够快。一旦用户 A 访问该网站,就会向用户 B 发送一个 UDP 数据包,请求自动登录。用户 B 通过访问 index.php?user=B&password=** 登录。这在不到 50 毫秒的时间内完成。为了保持这种性能,我必须每 51 毫秒循环一次 AJAX 查询。但是,如果 UDP 数据包丢失或有太多客户端尝试这样做,它会 DoS(拒绝服务)并杀死服务器。 不是多次查询,你能不能让当一个人登录时,他们的登录信息被广播给其他人? 嗨,保罗。是的,这应该工作。知道如何在 php 中做到这一点吗?【参考方案2】:在“等待”请求(用户 A)的代码中,创建一个新的侦听套接字 (http://php.net/manual/en/sockets.examples.php),该套接字绑定到不会与其他任何内容冲突的本地主机地址和端口(例如,127.12.34.56 端口) 7890) 然后通过调用 socket_accept 等待连接。如果已经有一个请求在该状态等待,这将失败,否则它将在那里等待连接。
在您的“信号”请求(用户 B)中,创建一个新套接字,并连接到您的侦听套接字。等待用户 A 请求的 PHP 处理程序将立即从它被阻止的 socket_accept 调用返回,您可以继续。如果您需要在两者之间传递任何消息,您可以简单地在套接字中读取和写入消息。
对于聊天室和显示服务器发送事件的通知页面等应用程序,这是一项非常常见的任务。与不断调用 sleep 并循环检查数据库或文件(或从 javascript 端循环向服务器发出许多请求)的轮询方法相比,这种方法有一些优点:
-不会创建不必要的 HTTP 请求或 DB 查询或消耗资源和网络流量的 CPU 循环
-当触发事件发生时立即动作,没有任何延迟
-它不依赖于数据库或文件
主要缺点是您的 PHP 必须具有打开套接字并连接到它们的权限,而在共享主机环境中通常不是这种情况。
例如,见https://gist.github.com/root9b/e1f0b82769296b06c079e53c7362bb94
【讨论】:
【参考方案3】:使用 sleep 和 db 怎么样?
客户端 1 登录,PHP 插入一个“等待条目”,然后以设定的时间间隔(可能使用 time_nanosleep)轮询数据库以获取标记为“完成”的内容。 客户端 2 登录,PHP 更新“等待条目”以将其设置为“完成”。 客户 1 看到流程已经完成,就愉快地继续前进。
如果您没有数据库,这可以通过一个简单的临时文件来完成。
【讨论】:
嗨 cwallenpoole。这是我想使用的解决方案。问题是每分钟会完成数万个请求,我需要 50 毫秒范围内的性能(但有些用户可能需要 20 秒或更长时间)。每隔 50 毫秒对数据库进行的任何“重复查询”都会对服务器造成 DoS(拒绝服务)。 我很害怕,这就是我推荐临时文件解决方案的原因。但是,对于 10k 请求/分钟,这可能也有点多。 我现在正在考虑两种选择。 1) 为支持 WaitForSingleObject API 的 php 编写一个 c 扩展或 2) 您的建议,但要使用共享内存段 php.net/manual/en/ref.sem.php,而不是文件或数据库。我相信我会选择#2,直到遇到障碍——如果有的话——如果它失败了,那么构建 c 扩展。由于定期查询共享内存只是简单的内存访问,我觉得应该没问题。【参考方案4】:您正在寻找守护进程,这里有一些如何创建它的信息:
http://kevin.vanzonneveld.net/techblog/article/create_daemons_in_php/
【讨论】:
运行我自己的守护进程将完全独立于 Apache,对吗?我使用 php 的主要原因是利用 Apache 提供的 http 工具。以上是关于PHP,暂停脚本执行,直到另一个正在运行的脚本发出事件信号?的主要内容,如果未能解决你的问题,请参考以下文章