exec() 应该是异步的,但它不是
exec() should be asynchronous, but it isn't
我正在使用 Yii 2 框架创建一个 Web 应用程序,运行使用 PHP 在 Apache 网络服务器上运行(服务器是 Ubuntu)。
该应用程序的很大一部分涉及用户上传视频,并且该视频通过 FFMpeg 运行 重新保存两次,一次作为 MP4,另一次作为 WEBM。 FFMpeg 还会提取一个框架,然后 运行 通过 Imagick 正确调整大小。
所有这些都需要花费大量时间,因此我没有向用户显示可能 5-10 分钟的加载屏幕,而是选择将所有处理放在控制台命令中,然后 运行s 在后台异步,并在他们的视频处理完成后通过电子邮件发送给他们。
上传表单模型的相关部分如下:
// if the new database entry successfully saved
if($video->save()){
// define the target filename and full target filepath
$target_name = uniqid();
$target_path = Yii::getAlias('@webroot'). '/videos/' . $target_name;
// get the current working directory (should be /models)
$cwd = getcwd();
// move up one directory to the app base
chdir('../');
// prepare the shell command to process the video
$command = escapeshellcmd("php yii video/process " . $fileFullPath . " " . $target_name . " " . $target_path . " " . $video->id . " " . $video->name . " " . Yii::$app->language . " " . Yii::$app->homeUrl . " " . $this->email . " >/dev/null 2>&1 &");
// execute the shell command
exec($command);
// change the working directory back to the original
chdir($cwd);
// return the ID of the uploaded video
return $video->id;
}
在 shell 命令的末尾,您可以看到 /dev/null 重定向应该会导致命令异步执行,从而允许 PHP 脚本继续执行并且 return上传到控制器的视频ID。
这里是 VideoController 方法 actionProcess 的一个稍微缩短的版本:
public function actionProcess($source_path, $target_name, $target_path, $id, $first_name, $language, $homeUrl, $email)
{
$ffmpeg = FFMpeg\FFMpeg::create(['timeout' => 7200, 'ffmpeg.threads' => 4]);
$video = $ffmpeg->open($source_path);
$dimension = new FFMpeg\Coordinate\Dimension(1280, 1280);
$video
->filters()
->resize($dimension, 'inset')
->synchronize();
$video
->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(2))
->save($target_path . '.png');
$video
->save(new FFmpeg\Format\Video\X264(), $target_path . '.mp4')
->save(new FFMpeg\Format\Video\WebM(), $target_path . '.webm');
@unlink($source_path);
$image = Imagick::open($target_path . '.png');
//////////
// There's a big if statement here controlling whether to crop the image vertically or horizontally to get the desired size.
// Didn't seem necessary to include.
//////////
$image->saveTo($target_path . '.png');
$video = Video::find()->where(['id' => $id])->one();
$video->path = $target_name;
$video->published = Video::IS_PUBLISHED;
$video->save();
//////////
// There's another large code block here to send an email to the user.
// Also didn't seem necessary to include.
//////////
return 0;
}
如您所知,我正在使用 PHP-FFmpeg 库 (https://github.com/PHP-FFMpeg/PHP-FFMpeg) to call FFMpeg, and I'm using tpmanc's Yii2 Imagick library (https://github.com/tpmanc/yii2-imagick) 来实现 Imagick。
综上所述:exec() 命令应该异步执行,但事实并非如此。上传视频会导致视频被上传,然后再等待 5-10 分钟,视频处理开始并完成,然后最终加载 'successfully uploaded' 页面。
事情是这样的:它正在工作。我在开发周期的早期就对其进行了测试,结果很好。然后我在 shell 命令上注释掉了 /dev/null 重定向,这样我就可以在开发时进行调试,现在我已经把它加回去了,它似乎不再起作用了。是什么导致上述命令不能异步执行?
编辑:我还应该补充一点,所做的唯一更改是对控制台执行的 PHP 脚本进行的。执行实际命令本身(上传表单模型)的脚本在工作和不工作之间没有任何变化。因此,要么我遗漏了一个明显的拼写错误,要么控制台命令中的某些内容覆盖了 /dev/null 重定向并强制表单模型等待脚本完成,这似乎实际上不应该可能,当然我在这方面可能是错的。
更新:我最终使用 Cron 来完成此操作,而不是在每次上传视频时手动调用脚本。也就是说,我认为这个问题应该保持开放,因为实际问题尚未解决:为什么上面的 exec() 不能异步执行?
最终编辑:好吧,反对票的小仙女们来了。考虑关闭问题。
我有同样的问题,几年前的视频。 PHP 不是异步的。我建议你使用 React PHP (http://reactphp.org/) 或创建 JobQueue and/or Cron 任务列表来处理它。您可以创建视频并上传,向用户展示视频,显示消息,"Rendering" 并在未为他创建缩略图时为视频创建示例缩略图。
我使用 Yii 到 JobQueue 创建了这个例子,但之后搜索更好。 https://github.com/yiisoft/yii2-queue
我正在使用 Yii 2 框架创建一个 Web 应用程序,运行使用 PHP 在 Apache 网络服务器上运行(服务器是 Ubuntu)。
该应用程序的很大一部分涉及用户上传视频,并且该视频通过 FFMpeg 运行 重新保存两次,一次作为 MP4,另一次作为 WEBM。 FFMpeg 还会提取一个框架,然后 运行 通过 Imagick 正确调整大小。
所有这些都需要花费大量时间,因此我没有向用户显示可能 5-10 分钟的加载屏幕,而是选择将所有处理放在控制台命令中,然后 运行s 在后台异步,并在他们的视频处理完成后通过电子邮件发送给他们。
上传表单模型的相关部分如下:
// if the new database entry successfully saved
if($video->save()){
// define the target filename and full target filepath
$target_name = uniqid();
$target_path = Yii::getAlias('@webroot'). '/videos/' . $target_name;
// get the current working directory (should be /models)
$cwd = getcwd();
// move up one directory to the app base
chdir('../');
// prepare the shell command to process the video
$command = escapeshellcmd("php yii video/process " . $fileFullPath . " " . $target_name . " " . $target_path . " " . $video->id . " " . $video->name . " " . Yii::$app->language . " " . Yii::$app->homeUrl . " " . $this->email . " >/dev/null 2>&1 &");
// execute the shell command
exec($command);
// change the working directory back to the original
chdir($cwd);
// return the ID of the uploaded video
return $video->id;
}
在 shell 命令的末尾,您可以看到 /dev/null 重定向应该会导致命令异步执行,从而允许 PHP 脚本继续执行并且 return上传到控制器的视频ID。
这里是 VideoController 方法 actionProcess 的一个稍微缩短的版本:
public function actionProcess($source_path, $target_name, $target_path, $id, $first_name, $language, $homeUrl, $email)
{
$ffmpeg = FFMpeg\FFMpeg::create(['timeout' => 7200, 'ffmpeg.threads' => 4]);
$video = $ffmpeg->open($source_path);
$dimension = new FFMpeg\Coordinate\Dimension(1280, 1280);
$video
->filters()
->resize($dimension, 'inset')
->synchronize();
$video
->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(2))
->save($target_path . '.png');
$video
->save(new FFmpeg\Format\Video\X264(), $target_path . '.mp4')
->save(new FFMpeg\Format\Video\WebM(), $target_path . '.webm');
@unlink($source_path);
$image = Imagick::open($target_path . '.png');
//////////
// There's a big if statement here controlling whether to crop the image vertically or horizontally to get the desired size.
// Didn't seem necessary to include.
//////////
$image->saveTo($target_path . '.png');
$video = Video::find()->where(['id' => $id])->one();
$video->path = $target_name;
$video->published = Video::IS_PUBLISHED;
$video->save();
//////////
// There's another large code block here to send an email to the user.
// Also didn't seem necessary to include.
//////////
return 0;
}
如您所知,我正在使用 PHP-FFmpeg 库 (https://github.com/PHP-FFMpeg/PHP-FFMpeg) to call FFMpeg, and I'm using tpmanc's Yii2 Imagick library (https://github.com/tpmanc/yii2-imagick) 来实现 Imagick。
综上所述:exec() 命令应该异步执行,但事实并非如此。上传视频会导致视频被上传,然后再等待 5-10 分钟,视频处理开始并完成,然后最终加载 'successfully uploaded' 页面。
事情是这样的:它正在工作。我在开发周期的早期就对其进行了测试,结果很好。然后我在 shell 命令上注释掉了 /dev/null 重定向,这样我就可以在开发时进行调试,现在我已经把它加回去了,它似乎不再起作用了。是什么导致上述命令不能异步执行?
编辑:我还应该补充一点,所做的唯一更改是对控制台执行的 PHP 脚本进行的。执行实际命令本身(上传表单模型)的脚本在工作和不工作之间没有任何变化。因此,要么我遗漏了一个明显的拼写错误,要么控制台命令中的某些内容覆盖了 /dev/null 重定向并强制表单模型等待脚本完成,这似乎实际上不应该可能,当然我在这方面可能是错的。
更新:我最终使用 Cron 来完成此操作,而不是在每次上传视频时手动调用脚本。也就是说,我认为这个问题应该保持开放,因为实际问题尚未解决:为什么上面的 exec() 不能异步执行?
最终编辑:好吧,反对票的小仙女们来了。考虑关闭问题。
我有同样的问题,几年前的视频。 PHP 不是异步的。我建议你使用 React PHP (http://reactphp.org/) 或创建 JobQueue and/or Cron 任务列表来处理它。您可以创建视频并上传,向用户展示视频,显示消息,"Rendering" 并在未为他创建缩略图时为视频创建示例缩略图。
我使用 Yii 到 JobQueue 创建了这个例子,但之后搜索更好。 https://github.com/yiisoft/yii2-queue