这正是在事件循环中执行任何操作时必须避免的问题:它不能被阻塞,因为任何其他人试图订阅、调用消息或其他任何事件驱动的事件都不会发生,直到这已经完成了。
这更像是一个架构问题,一旦你找到了最好的方法,那就是简化它并确保它适用于你需要的所有任务。
Ratchet 提供了一个ZMQ绑定——这太棒了,因为一旦你设置了它,你在端口 5555 上收到的任何东西都会在你的事件循环中触发onYourMethodName()
,或者你想调用它的任何东西!
考虑到这一点,您需要将需要完成的工作发送到作业队列,另一个进程(react 有它的子进程扩展,我不特别喜欢它,因为它在用户空间轮询而不是中断 -驱动 I/O,如 PHP 的PCNTL 扩展)或类似的。
如果您想“让它正常工作”,请启动需要完成的工作,以及连接 ID 或另一个 ID,以便您知道响应需要返回给谁,在子进程中以及何时完成发送出来。这不会阻塞!
如果您想以更好的方式做到这一点,我强烈建议您研究一下它及其架构,这样当您再次处理此类异步问题时,您可以将这些知识带入您的职业生涯,请采用“fire-and-and” -忘记'的方法。在事件循环中将需要完成的工作放入作业队列中,然后忘记它。
您的作业队列可以执行它的工作,完成后,通过 ZMQ(正在侦听的端口 5555,记住)触发结果,然后可以将数据发送回客户端。

对于一个关于工作队列的精彩演讲,我强烈推荐PHPNW 的这个。
最后一点,因为你打开了这个东西并在端口 5555 上监听数据,你可以从任何地方发送这个数据。它可以是进程间通信,就像你有一个将数据发送到端口 5555 的 java 应用程序,或者实际上是任何东西。它将事物绑定在一起,而不是耦合它们,这在您的架构中很重要。
对于实际使用 ZMQ 的示例,他们在此页面上提供了所有内容(如上链接),但我将尝试解释一下正在发生的事情。
$pull->bind('tcp://127.0.0.1:5555');
$pull->on('message', array($pusher, 'onYourMethodName'));
这部分意味着当任何东西向端口 5555 发送数据并且它是一条“消息”(您可以搜索其他可用选项而不是消息)时,它会调用onYourMethodName
您的$pusher
对象。真的就是这么简单。超过 5555 的任何内容都会命中$pusher::onYourMethodName
。
因此,您现在只需要在事件处理程序中创建您的方法(在 等旁边onMessage()
)onSubscribe()
......同样,该页面上都提到了这一点。
public function onYourMethodName($data)
{
/** You'll probably want to send the data in JSON format **/
/** Imagine you get through a 'topic' in here... **/
$data = json_decode($data, true);
/** You should already have stored the people who are connected, topics etc - see the tutorial **/
$topic = $this->subscribedTopics[$data['topic']];
/** Send the data out to everyone subscribed to this topic **/
$topic->broadcast($data);
}
如果您希望能够将数据发送给特定用户而不是所有人,那么有很多方法可以做到这一点。看看这个问题,了解我是如何做到的,但这已经是前一段时间了。
您现在唯一需要自己做的事情是,在您的处理程序中(在 onMessage 或其他中),实际上将需要完成的内容连同应该发送回的人(主题)一起放入队列中。
在你的工作人员完成它的工作并获取数据时,它需要调用它来访问我上面显示的代码:
$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_PUSH, 'my pusher');
$socket->connect("tcp://localhost:5555");
$socket->send(json_encode($data));
所以这就是你需要做的:
- 开始使用监听端口 5555
- 在您的事件处理程序等中创建您的方法
- 不用担心排队或其他任何事情
- 创建一个执行上述 4 行代码的非常简单的 php 脚本,并证明当您单独运行该脚本时,它确实将数据发送到您的事件循环中
- 然后担心如何将它添加到您的队列并让您的工作人员处理它