检测 PHP 代码块的超时
如果 PHP 中的代码块花费太长时间,有没有办法可以中止该代码块?也许是这样的:
//Set the max time to 2 seconds
$time = new TimeOut(2);
$time->startTime();
sleep(3)
$time->endTime();
if ($time->timeExpired()){
echo 'This function took too long to execute and was aborted.';
}
它不必完全像上面那样,但是是否有任何本地 PHP 函数或类可以执行类似的操作?
编辑:Ben Lee 使用 pcnt_fork
的回答将是完美的解决方案,只是它不适用于 Windows。有没有其他方法可以使用适用于 Windows 和 Linux 的 PHP 来完成此任务,但不需要外部库?
编辑2:XzKto的解决方案在某些情况下有效,但不一致,而且无论我尝试什么,我似乎都无法捕获异常。该用例正在检测单元测试的超时。如果测试超时,我想终止它,然后继续下一个测试。
Is there a way you can abort a block of code if it's taking too long in PHP? Perhaps something like:
//Set the max time to 2 seconds
$time = new TimeOut(2);
$time->startTime();
sleep(3)
$time->endTime();
if ($time->timeExpired()){
echo 'This function took too long to execute and was aborted.';
}
It doesn't have to be exactly like above, but are there any native PHP functions or classes that do something like this?
Edit: Ben Lee's answer with pcnt_fork
would be the perfect solution except that it's not available for Windows. Is there any other way to accomplish this with PHP that works for Windows and Linux, but doesn't require an external library?
Edit 2: XzKto's solution works in some cases, but not consistently and I can't seem to catch the exception, no matter what I try. The use case is detecting a timeout for a unit test. If the test times out, I want to terminate it and then move on to the next test.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您可以通过分叉进程,然后使用父进程来监视子进程来实现此目的。 pcntl_fork 是一种分叉进程的方法,所以你有两个近内存中的相同程序并行运行。唯一的区别是,在一个进程中,父进程 pcntl_fork 返回一个正整数,该整数对应于子进程的进程 ID。在另一个进程中,子进程
pcntl_fork
返回 0。这是一个示例:
这是基本结构。下一步是添加流程到期时间。你的东西将在子进程中运行,父进程将只负责监视和计时子进程。但是为了让一个进程(父进程)杀死另一个进程(子进程),需要有一个信号。信号是进程通信的方式,表示“你应该立即结束”的信号是SIGKILL。您可以使用 posix_kill 发送此信号。所以父进程应该等待 2 秒然后杀死子进程,如下所示:
You can do this by forking the process, and then using the parent process to monitor the child process. pcntl_fork is a method that forks the process, so you have two nearly identical programs in memory running in parallel. The only difference is that in one process, the parent,
pcntl_fork
returns a positive integer which corresponds to the process id of the child process. And in the other process, the child,pcntl_fork
returns 0.Here's an example:
That's the basic structure. Next step is to add a process expiration. Your stuff will run in the child process, and the parent process will be responsible only for monitoring and timing the child process. But in order for one process (the parent) to kill another (the child), there needs to be a signal. Signals are how processes communicate, and the signal that means "you should end immediately" is SIGKILL. You can send this signal using posix_kill. So the parent should just wait 2 seconds then kill the child, like so:
如果除了分叉之外,如果您在一个命令(例如 sleep())上编写暂停脚本,那么您实际上无法做到这一点,但是对于特殊情况,有很多解决方法:如果您在数据库查询上编程暂停,则像异步查询一样,如果您在数据库查询上暂停,则可以使用 proc_open程序在某些外部执行等处暂停。不幸的是,它们都是不同的,因此没有通用的解决方案。
如果你的脚本等待一个很长的循环/很多行代码,你可以做一个像这样的肮脏的把戏:
但我不认为它很好。如果您具体说明具体情况,我想我们可以更好地帮助您。
You can't really do that if you script pauses on one command (for example sleep()) besides forking, but there are a lot of work arounds for special cases: like asynchronous queries if you programm pauses on DB query, proc_open if you programm pauses at some external execution etc. Unfortunately they are all different so there is no general solution.
If you script waits for a long loop/many lines of code you can do a dirty trick like this:
but I don't think it is very good. If you specify the exact case I think we can help you better.
这是一个老问题,现在可能已经解决了很多次,但是对于寻找简单方法来解决这个问题的人来说,现在有一个库: PHP 调用程序。
This is an old question, and has probably been solved many times by now, but for people looking for an easy way to solve this problem, there is a library now: PHP Invoker.
如果执行时间超过限制,可以使用声明函数。 http://www.php.net/manual/en/control-structs .declare.php
这里有一个如何使用的代码示例
通过此代码,您将看到超时消息。
如果您想在声明块内获得长处理结果,您只需删除 sleep(5) 行或增加在脚本开头声明的最大执行时间
You can use declare function if the execution time exceeds the limits. http://www.php.net/manual/en/control-structures.declare.php
Here a code example of how to use
With this code you will see the timeout message.
If you want to get the Long process result inside the declare block you can just remove the sleep(5) line or increase the Max Execution Time declared at the start of the script
如果您不在其中,那么 set-time-limit 怎么样?安全模式。
What about set-time-limit if you are not in the safe mode.
大约两分钟就做好了,我忘了调用
$time->startTime();
所以我真的不知道到底花了多长时间;)和 演示。
我不太明白您的
endTime()
调用的作用,因此我改为使用checkTime()
,这也没有真正的目的,只是更新内部值。timeExpired()
会自动调用它,因为如果您忘记调用checkTime()
并且它使用的是旧时间,那么它肯定会很糟糕。Cooked this up in about two minutes, I forgot to call
$time->startTime();
so I don't really know exactly how long it took ;)And the demo.
I don't really get what your
endTime()
call does, so I madecheckTime()
instead, which also serves no real purpose but to update the internal values.timeExpired()
calls it automatically because it would sure stink if you forgot to callcheckTime()
and it was using the old times.您还可以使用第二个脚本,其中包含暂停代码,该代码通过设置了超时的curl 调用执行。另一个明显的解决方案是解决暂停的原因。
You can also use a 2nd script that has the pause code in it that is executed via a curl call with a timeout set. The other obvious solution is to fix the cause of the pause.
这是我的方法。感谢其他人的回答:
那你可以尝试这样:
Here is my way to do that. Thanks to others answers:
Then you can try like this:
我使用 pcntl_fork 和 lockfile 在 php 中编写了一个脚本来控制超时后执行终止操作的外部调用的执行。
测试脚本run.php
I made a script in php using pcntl_fork and lockfile to control the execution of external calls doing the kill after the timeout.
Test Script run.php