BSD 上的 PHP 后台进程使用 100% CPU

发布于 2024-12-10 01:36:50 字数 439 浏览 2 评论 0原文

我有一个作为后台进程运行的 PHP 脚本。该脚本仅使用 fopen 从 Twitter Streaming API 读取。本质上是一个永不结束的 http 连接。不幸的是,我无法发布该脚本,因为它是专有的。 Ubuntu 上的脚本运行正常,占用的 CPU 很少。然而在 BSD 上,脚本总是使用接近 100% 的 CPU。该脚本在两台机器上都运行良好,并且是完全相同的脚本。谁能想到一些可能为我指明解决此问题的正确方向的方法?这是我编写的第一个在后台持续运行的 PHP 脚本。

该脚本是一个无限循环,它每分钟读取数据并写入 json 文件。每当重新连接发生时,脚本就会写入 MySQL 数据库,这通常是在运行几天后。该脚本没有做任何其他事情,而且也不是很长。我对 BSD 或编写运行无限循环的 PHP 脚本缺乏经验。预先感谢您的任何建议,请告诉我这是否属于另一个 StackExchange。我会尽力尽快回答任何问题,因为我意识到这个问题非常模糊。

I have a PHP script that runs as a background process. This script simply uses fopen to read from the Twitter Streaming API. Essentially an http connection that never ends. I can't post the script unfortunately because it is proprietary. The script on Ubuntu runs normally and uses very little CPU. However on BSD the script always uses nearly a 100% CPU. The script is working just fine on both machines and is the exact same script. Can anyone think of something that might point me in the right direction to fix this? This is the first PHP script I have written to consistently run in the background.

The script is an infinite loop, it reads the data out and writes to a json file every minute. The script will write to a MySQL database whenever a reconnect happens, which is usually after days of running. The script does nothing else and is not very long. I have little experience with BSD or writing PHP scripts that run infinite loops. Thanks in advance for any suggestions, let me know if this belongs in another StackExchange. I will try to answer any questions as quickly as possible, because I realize the question is very vague.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情绪操控生活 2024-12-17 01:36:50

在不查看脚本的情况下,很难给您明确的答案,但是您需要做的是确保您的脚本正在适当地等待数据。您绝对不应该做的是在文件上调用 stream_set_timeout($fp, 0);stream_set_blocking($fp, 0);指针。

执行此类操作以避免赛车的脚本的基本结构如下所示:

// Open the file pointer and set blocking mode
$fp = fopen('http://www.domain.tld/somepage.file','r');
stream_set_timeout($fp, 1);
stream_set_blocking($fp, 1);

while (!feof($fp)) { // This should loop until the server closes the connection

  // This line should be pretty much the first line in the loop
  // It will try and fetch a line from $fp, and block for 1 second
  // or until one is available. This should help avoid racing
  // You can also use fread() in the same way if necessary
  if (($str = fgets($fp)) === FALSE) continue;

  // rest of app logic goes here

}

您也可以使用 sleep()/usleep() 来避免赛车,但更好的方法是依靠阻塞函数调用来执行阻塞。如果它在一种操作系统上工作但在另一种操作系统上不起作用,请尝试显式设置阻止模式/行为,如上所述。

如果您无法通过调用传递 HTTP URL 的 fopen() 来实现此功能,则可能是 PHP 中的 HTTP 包装器实现存在问题。要解决此问题,您可以使用 fsockopen() 并自行处理请求。这并不太困难,特别是当您只需要发送单个请求并读取恒定流响应时。

Without seeing the script, this is very difficult to give you a definitive answer, however what you need to do is ensure that your script is waiting for data appropriately. What you should absolutely definitely not do is call stream_set_timeout($fp, 0); or stream_set_blocking($fp, 0); on your file pointer.

The basic structure of a script to do something like this that should avoid racing would be something like this:

// Open the file pointer and set blocking mode
$fp = fopen('http://www.domain.tld/somepage.file','r');
stream_set_timeout($fp, 1);
stream_set_blocking($fp, 1);

while (!feof($fp)) { // This should loop until the server closes the connection

  // This line should be pretty much the first line in the loop
  // It will try and fetch a line from $fp, and block for 1 second
  // or until one is available. This should help avoid racing
  // You can also use fread() in the same way if necessary
  if (($str = fgets($fp)) === FALSE) continue;

  // rest of app logic goes here

}

You can use sleep()/usleep() to avoid racing as well, but the better approach is to rely on a blocking function call to do your blocking. If it works on one OS but not on another, try setting the blocking modes/behaviour explicitly, as above.

If you can't get this to work with a call to fopen() passing a HTTP URL, it may be a problem with the HTTP wrapper implementation in PHP. To work around this, you could use fsockopen() and handle the request yourself. This is not too difficult, especially if you only need to send a single request and read a constant stream response.

凉栀 2024-12-17 01:36:50

在我看来,你的函数之一在 Linux 上短暂阻塞,但在 BSD 上却没有。如果没有看到您的脚本,很难具体说明,但我建议的一件事是添加 usleep() 在下一次循环迭代之前:

usleep(100000); //Sleep for 100ms

您不需要长时间睡眠...只需足够的时间,以便您不会使用 100% CPU。

编辑:既然您提到您现在没有好的方法在后台运行它,我建议您查看本教程“守护”您的脚本。其中包括一些用于执行此操作的方便代码。它甚至可以为您在 init.d 中创建一个文件。

It sounds to me like one of your functions is blocking briefly on Linux, but not BSD. Without seeing your script it is hard to get specific, but one thing I would suggest is to add a usleep() before the next loop iteration:

usleep(100000); //Sleep for 100ms

You don't need a long sleep... just enough so that you're not using 100% CPU.

Edit: Since you mentioned you don't have a good way to run this in the background right now, I suggest checking out this tutorial for "daemonizing" your script. Included is some handy code for doing this. It can even make a file in init.d for you.

最后的乘客 2024-12-17 01:36:50

实际阅读时代码看起来如何?你是否只是敲击插座直到得到东西为止?

解决这个问题的一种真正有效的方法是使用 libevent 扩展,但这不适合弱者有心。

How does the code look like that does the actual reading? Do you just hammer the socket until you get something?

One really effective way to deal with this is to use the libevent extension, but that's not for the feeble minded.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文