当一个代码部分的执行时间超过指定的时间限制时,是否可以终止它?

问题描述 投票:4回答:3

我目前正在我的CMS应用程序中开发一个计划任务(如cronjobs)系统。我想知道,当一段代码的执行时间超过指定的时间限制时,是否有可能终止它。

有些预定的任务可能很重,一个任务可能会运行到一个无限循环,说得简单点,有很多原因会导致任务占用很多时间。这样做的几个问题之一是,任务会占用比实际需要的资源多得多的资源,从而降低了它所运行的服务器的性能,这将使CMS和网站本身的可靠性降低。

想象一下这个系统,如下所示。一旦计划任务管理器被触发, 它将执行所有的任务 在那里计划的时间。想象一个简单的for循环,它将执行每个任务,同步,一个接一个。想象一下这个简单的例子。

// This array would contain an array with all scheduled tasks that should be executed.
$tasks = Array();

// Loop through each task
foreach($tasks as $t) {
    // Execute the task
    $t->execute();
}

现在, $task->execute(); 方法使PHP的解释器等待直到任务的代码被执行。我的问题是,是否有任何方法可以终止运行在 execute(); 方法,如果它的执行时间超过了指定时间。

例如,如果提供了10秒的时间限制,而一个任务的代码执行时间超过了30秒,那么任务的运行代码应该在10秒后终止,以允许任务调度器继续下一个任务。

可以在每个调度任务的代码里面实现这个功能,用一个简单的if-statement来实现,这个if-statement会在每次执行一部分代码的时候检查时间。问题是,这需要在每个任务的代码中实现,因为这个系统的目的是让第三方开发者正确地使用这些任务来实现他们的插件。我不喜欢 "强迫 "所有使用任务的开发者去实现这些功能。

我知道 set_time_limit(); 方法,但问题是这个方法会终止整个会话,而不是那个方法,这就是为什么这个方法不能解决这个问题。

php timeout scheduled-tasks limit
3个回答
3
投票

将我的评论 "移植 "到答案中。

这是另一个问题 是非常相似的。

PHP的默认实现是在一个线程中运行脚本,所以它是 不可能 来取消脚本本身的代码执行。只有 非常非常 很少有PHP函数支持异步操作,例如,你可以使用 mysqlnd但是这个特殊的功能是mysql驱动的一部分,而不是PHP。

有一些扩展可以引入 多线程 到PHP,即 pthread. 要推荐另一个来源,请阅读 本回答 由扩展的作者提供。

不幸的是,对于一个 "主流 "项目(应该尽可能在通用的设置上运行),使用 pthreads 是做不到的。该扩展不太可能安装在任何共享的web空间上。

此外,请记住,线程安全编程(或称 脚本 对于那些关心的人来说)是一项严肃的任务,你必须关心它。这意味着要准备好你的线程代码,使其不会锁定等待对方(僵局)、破坏对方的数据等。术语的详细解答。安全线 可见 此处.

彻底地思考所涉及的工作,搞砸一些事情的风险,以及使用线程的收益。确保你的愿望真的重要到可以引入复杂的线程。


2
投票

我遇到过这样的问题,我有一招可以解决这个问题。我的变通方法是,我用cURL执行本地脚本是这样的。

// This is the curl call which will execute the local script
$execute_script = curl_call('local_script.php');

在'local_script.php'文件里有这样的执行代码

// In local_script.php
// Set time limit
set_time_limit(10);
// Execute task
$task->execute();
// Print 1 to let the curl call know that the script executed at the right time
echo '1';

然后,在cURL调用部分,你可以在返回 "1 "的时候检查脚本是否执行得很好

if ($execute_script == '1'){
  // Successful script
} else {
  // Timed out
}

希望能帮到你


2
投票

如果超过了时间,你可以直接中断循环。

$max = 10; //maximum time in seconds
$start = microtime(true);
foreach($tasks as $t) {
    // Execute the task
    $t->execute();
    if (microtime(true) - $start > $max) {
        break;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.