我是做前端的,会点 PHP,但不打算花太多时间深入学 PHP (正在学 Python ),所以想问问有没有捷径。
最近做个小项目,用 PHP 输出 JSON 并发送邮件,大概逻辑是这样的:
处理 JSON...
返回 JSON...
发邮件(调用 PHPMailer )...
但是这样的话会等待发邮件任务完成在返回 JSON,想知道有什么方法可以先返回(即结束当前脚本),在处理发邮件的任务?
![]() | 1 vus520 2017-04-27 18:16:56 +08:00 你把要发的邮件写到数据库(队列)中,然后有一个独立的程序在后台循环读队列,发邮件就行。 所谓的异步,总是离不开队列。 |
![]() | 2 yxslnmp 2017-04-27 18:22:27 +08:00 swoole... 简单的就用 redis 处理吧 |
![]() | 4 xifangczy 2017-04-27 18:39:51 +08:00 |
![]() | 5 lights 2017-04-27 18:47:54 +08:00 首先要有一个队列, 简单的比如 redis, rabbitMQ 其实也很简单 然后主程序将需要发送的邮件内容啊主题啊收件人啊一些信息写到队列里 有另外一个常驻的程序监听这个队列, 并发送邮件 于是就实现了异步啦, 啦啦~~ |
![]() | 6 orderc 2017-04-27 18:48:33 +08:00 php-resque 轻量级的消息队列 |
![]() | 7 bianhua 2017-04-27 18:53:09 +08:00 @cstome 简单的答案是没有。 当然你不在乎把你的处理流程变乱,方法还是有的: 你需要发送 Connection: Close 和 Content-Length 头,设置 set_time_limit、ignore_user_abort,然后用 flush (以及 ob_flush )冲洗缓冲。 这样你的代码在用户浏览器断开之后还能在运行一段时间。 不过这样会导致很多问题,首先运行那段 PHP 代码的进程或线程会阻塞,导致服务器处理效率变低,其次它所占用的内存一直无法被释放。这两条加起来可能会导致 DoS 弱点。 如果是虚拟主机,其实可以想办法写个远程队列服务,或用云邮件服务来解决发送邮件时阻塞的问题(发送 HTTP 请求的延时在绝大多数情况下会比一次 SMTP 会话的延时小一些)。 |
![]() | 8 R18 2017-04-27 18:56:04 +08:00 via Android |
![]() | 10 yangyao 2017-04-27 19:46:02 +08:00 pclose(popen("php -f sendmail.php","r")); |
![]() | 11 sumuu 2017-04-27 20:05:04 +08:00 |
![]() | 12 lygmqkl 2017-04-27 20:07:09 +08:00 via iPhone 借助数据库完成队列,然后 cli 进行发送,如果需要 feedback cli 再更新下数据库记录结果。 ps cli 是多线程,性能不错。可以实现多服务器异架构。也可以把这里 cli 换成 py nodejs go |
13 keller 2017-04-27 20:37:00 +08:00 怎么不用 node ? |
![]() | 14 eoo 2017-04-27 20:4:26 +08:00 via Android 前端 干嘛不试试 nodejs ? |
![]() | 15 mchl 2017-04-27 20:45:45 +08:00 via Android laravel queue |
![]() | 16 murusu 2017-04-27 20:48:36 +08:00 ![]() 只能用虚机的话就只能换个想法实现了,你看看这样子行不 PHP 输出 JSON JSON 存入数据库并返回 JSON 并附带 KEY 浏览器以 KEY 异步调用另一段 PHP 脚本发送邮件 邮件发送成功返回 |
![]() | 17 cxbig 2017-04-27 20:50:36 +08:00 你说的不会是 Host 吧?至少也得换成 VPS 前端干嘛折腾 PHP,用 Node 多好 比方说用 AWS 的解决方案,SQS 保存队列,Lambda 来跟进处理,发邮件可以 用 SNS。 |
![]() | 18 zhs227 2017-04-27 20:52:08 +08:00 虚拟主机的话在请求量不大情况下可以先 ob_flush,然后把线程挂着去发邮件。 访问量大的话就建议至少弄个 vps,不要玩虚拟主机了。 |
![]() | 19 shiny 2017-04-27 20:58:34 +08:00 为啥不用成熟的邮件发送接口,丢给他们去处理。他们有自己的队列。 |
![]() | 20 FarAhead 2017-04-27 21:09:20 +08:00 PHP 不能 fork 一个然后在里面执行吗 |
![]() | 21 kran 2017-04-27 21:32:50 +08:00 via Android ![]() fastcgi_finish_request |
22 hainuo 2017-04-27 21:59:12 +08:00 via iPhone 有两个东西可以做到 异步编程对 php 来说是服务端变成 你可以看一下 reactphp swoole workman 等 |
![]() | 24 sagaxu 2017-04-27 23:13:20 +08:00 PHP 太残了,别的语言一个线程池和 Queue 就搞定的事,到了 php 这里还要各种绕路 |
25 jssngz 2017-04-27 23:26:03 +08:00 via Android php 看了语法和 jsp asp 是一个等级的,还没有到语言的层级 |
26 dream7758521 2017-04-28 02:04:59 +08:00 via Android 教你一个最简单的方法,先处理完 json,然后将相关信息存到数据库。 然后在写一个单独处理邮件发送的 php,在这个页面最后面加入跳转到本页的功能, 然后用浏览器打开这一页 php,放着别动就可以了,发送完毕后又会自动跳转到本页,然后又会继续运行! |
27 Mitt 2017-04-28 02:46:55 +08:00 ![]() |
![]() | 28 dangyuluo 2017-04-28 07:20:45 +08:00 beanstalkd |
30 simapple 2017-04-28 08:07:26 +08:00 gearman |
31 wwolf 2017-04-28 08:11:13 +08:00 swoole |
32 MushishiXian 2017-04-28 08:12:01 +08:00 别人问个 php 问题都有人黑语言的,也不看自己什么水平,就说一门语言怎样怎样 |
![]() | 33 jininij 2017-04-28 08:46:11 +08:00 via Android yield 协程可以实现异步。伪代码长这样 function sendEmail($argv){ $message = yield ; //1.发送邮件 sleep(3); } $y = sendEmail($a); //前期工作 $y->send($m); //2.其他工作,输出内容。 sleep(2); 1 和 2 会在不同线程中执行,脚本实际执行时间是 1 和 2 中最长的。3 秒,而不是 5 秒。 |
34 KAAAsS 2017-04-28 08:50:39 +08:00 ignore_user_abortb 吧……但是还是考虑考虑 VPS 吧 |
35 ic2y 2017-04-28 09:04:06 +08:00 都做成 ajax 调用。后两部 分拆为两个 ajax。 |
![]() | 36 silenceeeee 2017-04-28 09:04:50 +08:00 private $_queue = array(); function send() { // ... // echo JSON // $this->_queue[] = array('addr'=> '[email protected]', ...); } public function __destruct() { // send email } |
![]() | 37 mikej 2017-04-28 09:14:22 +08:00 可以试试 fastcgi_finish_request,看鸟哥的 blog: http://www.laruence.com/2011/04/13/1991.html |
![]() | 38 Felldeadbird 2017-04-28 09:15:29 +08:00 我司是这么处理的。 用户触发发送邮件(通知类)。先将待发送的内容保存到数据库(缓存)。然后马上返回给前台告知操作成功。 后台有 cron 定时去处理这些任务。 |
![]() | 39 GG668v26Fd55CP5W 2017-04-28 09:36:25 +08:00 via iPhone 用 ajax 处理队列的做法我好像在某个 O2O 系统看过。 |
![]() | 40 tabris17 2017-04-28 09:42:04 +08:00 传统 cli 或者 fcgi 模式的 PHP 是不支持异步的,可以用 Swoole 或者 workerman |
![]() | 41 barbery 2017-04-28 10:09:16 +08:00 这个用队列不就完了? |
![]() | 42 dryyun 2017-04-28 10:58:28 +08:00 既然是小项目,为什么要做的那么复杂。发个邮件能用多久呢。。 直接 try{ 发邮件。。 }catch(){ ... } 发邮件能成功就是很快的,不能成功,就是会报错,干脆发邮件超时时间设的稍微短一点,不就解决问题了。 |
![]() | 47 qieqie 2017-04-28 11:33:19 +08:00 @jininij 你这是把 php 脑补成 go 了,generator 需要你手动调度自己实现协程,也依赖更底层的异步 io 接口(换句话说就是支持 non-blocking io 扩展或者用 libevent 这样的事件通知库自己实现) |
![]() | 48 tkisme 2017-04-28 13:15:03 +08:00 celery |
![]() | 49 flowfire 2017-04-28 18:12:10 +08:00 via iPhone nodejs 大法好 我自从用了 node 就再也不想碰 php 了 |
![]() | 50 xiaotianhu 2017-04-28 22:57:14 +08:00 fastcgi_finish_request 最简单的套路 |
![]() | 51 abcbuzhiming 2017-05-04 11:34:50 +08:00 php 的异步都是扯淡的,不借助队列压根没办法,除非你能自己写插件,所以简单的就搞个队列比如 redis,复杂的。。 |
52 nobird 2017-05-16 01:33:35 +08:00 via iPhone 需要发送的邮件内容存入数据库 当作一个队列处理 有访客访问页面的时候 每个页面刷新就发送一个邮件 小规模使用的话 效果还不错 |
53 arist 2017-05-16 15:03:17 +08:00 我司是这样处理, 1. 把消息写入数据库队列 2. 使用 fsockopen 异步调用消息处理的程序,这个相当于非阻塞的模式,不需等待远端返回。 3. 直接返回成功 |
![]() | 54 wizardforcel 2017-05-19 18:23:22 +08:00 via Android 你应该听说过一个词,queue based architecture。 |
55 cccoco123 2017-07-18 17:30:16 +08:00 https://github.com/fucongcong/Group-Co 异步协程框架,SOA 服务化调用,支持并行、串行调用。支持异步日志,异步文件读写,异步 Mysql,异步 Redis,Mysql,Redis 连接池 |