我想使用
Fiber
(PHP 8.1)创建一个线程来发送电子邮件(电子邮件发送需要10秒,所以我决定使用线程)。这是我的代码
<?php
$fiber = new Fiber(function () {
send_email();
});
$fiber->start();
exit(json_encode(['response' => 1]));
send_email()
的结果并不重要,但启动光纤后,光纤会等到send_email()
完成然后exit(json_encode(['response' => 1]));
发生!!!!我希望它立即退出,但也发送电子邮件!
有什么问题吗?
根据 https://www.php.net/manual/en/language.fibres.php Fiber 是可中断的,但没有提到它是完全异步或多线程 - 它不允许 main 函数继续自动执行...根据我的阅读,只有在您暂停 Fiber 时才会发生 - 事实上,这就是您在代码中报告的体验。
PHP 是单线程的,并且没有任何类型的适当的基于任务的异步编程模型(不幸的是,与其他服务器端语言(如 NodeJS 或 C#)相比,这是现在的一个主要弱点)。
https://php.watch/versions/8.1/fibres也说
重要的是并发执行并不意味着同时 执行。 Fiber 和主执行流程不会发生在 同一时间。由主执行流程来启动 Fiber, 当它启动时,Fiber 会被独占执行。
和
Fiber 本身不允许同时执行多个 Fiber 或主线程和一个 Fiber。
...所以我认为您可能误解了此功能及其功能 - 它无法帮助您满足您的要求。
据我所知,使用 PHP 不可能做你正在尝试的事情。更好的解决方案可能是将电子邮件发送给单独的进程 - 例如由
cron
触发的后台任务。这是一个相当典型的模式:PHP 收到一个请求,要求它发送电子邮件。它将请求记录在数据库表中,然后退出。后台任务按计划执行,从数据库表中提取所有未完成的任务并运行它们,然后更新表以表明它们已完成。这样,如果后台任务花费更长的时间,其实并不重要,因为它不会减慢网站或最终用户的速度。
这是一个老问题,但您可以使用
fastcgi_finish_request()
功能向用户发送响应并继续进行其他操作。
您可以阅读此回复https://stackoverflow.com/a/4236290/1931953