cstome
V2EX  ›  PHP

PHP 有没有类似异步的功能?

  •  
  •   cstome · Apr 27, 2017 · 10974 views
    This topic created in 3478 days ago, the information mentioned may be changed or developed.

    大概情况

    我是做前端的,会点 PHP,但不打算花太多时间深入学 PHP (正在学 Python ),所以想问问有没有捷径。

    大概需求

    最近做个小项目,用 PHP 输出 JSON 并发送邮件,大概逻辑是这样的:

    处理 JSON...

    返回 JSON...

    发邮件(调用 PHPMailer )...

    但是这样的话会等待发邮件任务完成在返回 JSON,想知道有什么方法可以先返回(即结束当前脚本),在处理发邮件的任务?

    Supplement 1  ·  Apr 27, 2017
    16 楼的这个思路很可以:

    只能用虚机的话就只能换个想法实现了,你看看这样子行不
    PHP 输出 JSON
    JSON 存入数据库并返回 JSON 并附带 KEY
    浏览器以 KEY 异步调用另一段 PHP 脚本发送邮件
    邮件发送成功返回
    55 replies  •  2017-07-18 17:30:16 +08:00
    vus520
    vus520
    Apr 27, 2017
    1
    你把要发的邮件写到数据库(队列)中,然后有一个独立的程序在后台循环读队列,发邮件就行。

    所谓的异步,总是离不开队列。
    yxslnmp
    yxslnmp
    Apr 27, 2017
    2
    swoole...
    简单的就用 redis 处理吧
    cstome
    cstome
    OP
    Apr 27, 2017
    3
    @vus520 由于使用虚拟主机,所以似乎没法开个进程在后台。。。
    xifangczy
    xifangczy
    Apr 27, 2017
    4
    1、ajax
    2、flush http://php.net/manual/zh/function.flush.php
    3、swoole...
    lights
    lights
    Apr 27, 2017
    5
    首先要有一个队列, 简单的比如 redis, rabbitMQ 其实也很简单
    然后主程序将需要发送的邮件内容啊主题啊收件人啊一些信息写到队列里
    有另外一个常驻的程序监听这个队列, 并发送邮件

    于是就实现了异步啦, 啦啦~~
    orderc
    orderc
    Apr 27, 2017
    6
    php-resque 轻量级的消息队列
    bianhua
    bianhua
    Apr 27, 2017
    7
    @cstome 简单的答案是没有。

    当然你不在乎把你的处理流程变乱,方法还是有的:
    你需要发送 Connection: Close 和 Content-Length 头,设置 set_time_limit、ignore_user_abort,然后用 flush (以及 ob_flush )冲洗缓冲。

    这样你的代码在用户浏览器断开之后还能在运行一段时间。

    不过这样会导致很多问题,首先运行那段 PHP 代码的进程或线程会阻塞,导致服务器处理效率变低,其次它所占用的内存一直无法被释放。这两条加起来可能会导致 DoS 弱点。

    如果是虚拟主机,其实可以想办法写个远程队列服务,或用云邮件服务来解决发送邮件时阻塞的问题(发送 HTTP 请求的延时在绝大多数情况下会比一次 SMTP 会话的延时小一些)。
    R18
    R18
    Apr 27, 2017 via Android
    8
    vus520
    vus520
    Apr 27, 2017
    9
    @cstome

    都有这样的业务需求了,还在用虚拟主机,我服你。
    yangyao
    yangyao
    Apr 27, 2017
    10
    pclose(popen("php -f sendmail.php","r"));
    lygmqkl
    lygmqkl
    Apr 27, 2017 via iPhone
    12
    借助数据库完成队列,然后 cli 进行发送,如果需要 feedback cli 再更新下数据库记录结果。

    ps cli 是多线程,性能不错。可以实现多服务器异歩架构。也可以把这里 cli 换成 py nodejs go
    keller
    keller
    Apr 27, 2017
    13
    怎么不用 node ?
    eoo
    eoo
    Apr 27, 2017 via Android
    14
    前端 干嘛不试试 nodejs ?
    mchl
    mchl
    Apr 27, 2017 via Android
    15
    laravel queue
    murusu
    murusu
    Apr 27, 2017❤️1
    16
    只能用虚机的话就只能换个想法实现了,你看看这样子行不
    PHP 输出 JSON
    JSON 存入数据库并返回 JSON 并附带 KEY
    浏览器以 KEY 异步调用另一段 PHP 脚本发送邮件
    邮件发送成功返回
    cxbig
    cxbig
    Apr 27, 2017
    17
    你说的不会是 Host 吧?至少也得换成 VPS
    前端干嘛折腾 PHP,用 Node 多好
    比方说用 AWS 的解决方案,SQS 保存队列,Lambda 来跟进处理,发邮件可以 用 SNS。
    zhs227
    zhs227
    Apr 27, 2017
    18
    虚拟主机的话在请求量不大情况下可以先 ob_flush,然后把线程挂着去发邮件。
    访问量大的话就建议至少弄个 vps,不要玩虚拟主机了。
    shiny
    shiny
    PRO
    Apr 27, 2017
    19
    为啥不用成熟的邮件发送接口,丢给他们去处理。他们有自己的队列。
    FarAhead
    FarAhead
    Apr 27, 2017
    20
    PHP 不能 fork 一个然后在里面执行吗
    kran
    kran
    Apr 27, 2017 via Android❤️1
    21
    fastcgi_finish_request
    hainuo
    hainuo
    Apr 27, 2017 via iPhone
    22
    有两个东西可以做到 异步编程对 php 来说是服务端变成 你可以看一下 reactphp swoole workman 等
    cstome
    cstome
    OP
    Apr 27, 2017
    23
    @murusu 这个思路很可以!
    sagaxu
    sagaxu
    Apr 27, 2017
    24
    PHP 太残了,别的语言一个线程池和 Queue 就搞定的事,到了 php 这里还要各种绕路
    jssngz
    jssngz
    Apr 27, 2017 via Android
    25
    php 看了语法和 jsp asp 是一个等级的,还没有到语言的层级
    dream7758521
    dream7758521
    Apr 28, 2017 via Android
    26
    教你一个最简单的方法,先处理完 json,然后将相关信息存到数据库。
    然后在写一个单独处理邮件发送的 php,在这个页面最后面加入跳转到本页的功能,
    然后用浏览器打开这一页 php,放着别动就可以了,发送完毕后又会自动跳转到本页,然后又会继续运行!
    Mitt
    Mitt
    Apr 28, 2017❤️1
    27
    @jssngz
    @sagaxu

    本来 PHP 设计也不是来干这种事的呀 选语言也要先搞清楚自己需要什么把 动不动就把一个语言说的那么残废 总想要个万能语言又想成本低又简单
    dangyuluo
    dangyuluo
    Apr 28, 2017
    28
    beanstalkd
    dangyuluo
    dangyuluo
    Apr 28, 2017
    29
    @sagaxu
    @jssngz

    两位大神,服。
    simapple
    simapple
    Apr 28, 2017
    30
    gearman
    wwolf
    wwolf
    Apr 28, 2017
    31
    swoole
    MushishiXian
    MushishiXian
    Apr 28, 2017
    32
    别人问个 php 问题都有人黑语言的,也不看自己什么水平,就说一门语言怎样怎样
    jininij
    jininij
    Apr 28, 2017 via Android
    33
    yield 协程可以实现异步。伪代码长这样

    function sendEmail($argv){
    $message = yield ;
    //1.发送邮件
    sleep(3);
    }
    $y = sendEmail($a);
    //前期工作
    $y->send($m);
    //2.其他工作,输出内容。
    sleep(2);

    1 和 2 会在不同线程中执行,脚本实际执行时间是 1 和 2 中最长的。3 秒,而不是 5 秒。
    KAAAsS
    KAAAsS
    Apr 28, 2017
    34
    ignore_user_abortb 吧……但是还是考虑考虑 VPS 吧
    ic2y
    ic2y
    Apr 28, 2017
    35
    都做成 ajax 调用。后两部 分拆为两个 ajax。
    silenceeeee
    silenceeeee
    Apr 28, 2017
    36
    private $_queue = array();
    function send() {
    // ...
    // echo JSON
    // $this->_queue[] = array('addr'=> '[email protected]', ...);
    }

    public function __destruct() {
    // send email
    }
    mikej
    mikej
    Apr 28, 2017
    37
    可以试试 fastcgi_finish_request,看鸟哥的 blog: http://www.laruence.com/2011/04/13/1991.html
    Felldeadbird
    Felldeadbird
    Apr 28, 2017
    38
    我司是这么处理的。
    用户触发发送邮件(通知类)。先将待发送的内容保存到数据库(缓存)。然后马上返回给前台告知操作成功。
    后台有 cron 定时去处理这些任务。
    GG668v26Fd55CP5W
    GG668v26Fd55CP5W
    Apr 28, 2017 via iPhone
    39
    用 ajax 处理队列的做法我好像在某个 O2O 系统看过。
    tabris17
    tabris17
    Apr 28, 2017
    40
    传统 cli 或者 fcgi 模式的 PHP 是不支持异步的,可以用 Swoole 或者 workerman
    barbery
    barbery
    Apr 28, 2017
    41
    这个用队列不就完了?
    dryyun
    dryyun
    Apr 28, 2017
    42
    既然是小项目,为什么要做的那么复杂。发个邮件能用多久呢。。
    直接 try{
    发邮件。。
    }catch(){
    ...
    }
    发邮件能成功就是很快的,不能成功,就是会报错,干脆发邮件超时时间设的稍微短一点,不就解决问题了。
    iyaozhen
    iyaozhen
    Apr 28, 2017 via Android
    43
    @kran 这个比较简单。先给前端返回数据,然后再发送邮件,完成后进程才会退出。
    silva
    silva
    Apr 28, 2017
    44
    @R18 我看你给出的链接里不是说明 PHP 有 pcntl_fork()接口么,为何他们都说的那么绕呢?
    R18
    R18
    Apr 28, 2017
    45
    @silva 我也不晓得,可能不符合实际场景吧
    suconghou
    suconghou
    Apr 28, 2017
    46
    @jininij 然而并不是
    qieqie
    qieqie
    Apr 28, 2017
    47
    @jininij 你这是把 php 脑补成 go 了,generator 需要你手动调度自己实现协程,也依赖更底层的异步 io 接口(换句话说就是支持 non-blocking io 扩展或者用 libevent 这样的事件通知库自己实现)
    tkisme
    tkisme
    Apr 28, 2017
    48
    celery
    flowfire
    flowfire
    Apr 28, 2017 via iPhone
    49
    nodejs 大法好
    我自从用了 node 就再也不想碰 php 了
    xiaotianhu
    xiaotianhu
    Apr 28, 2017
    50
    fastcgi_finish_request 最简单的套路
    abcbuzhiming
    abcbuzhiming
    May 4, 2017
    51
    php 的异步都是扯淡的,不借助队列压根没办法,除非你能自己写插件,所以简单的就搞个队列比如 redis,复杂的。。
    nobird
    nobird
    May 16, 2017 via iPhone
    52
    需要发送的邮件内容存入数据库 当作一个队列处理 有访客访问页面的时候 每个页面刷新就发送一个邮件 小规模使用的话 效果还不错
    arist
    arist
    May 16, 2017
    53
    我司是这样处理,
    1. 把消息写入数据库队列
    2. 使用 fsockopen 异步调用消息处理的程序,这个相当于非阻塞的模式,不需等待远端返回。
    3. 直接返回成功
    wizardforcel
    wizardforcel
    May 19, 2017 via Android
    54
    你应该听说过一个词,queue based architecture。
    cccoco123
    cccoco123
    Jul 18, 2017
    55
    https://github.com/fucongcong/Group-Co
    异步协程框架,SOA 服务化调用,支持并行、串行调用。支持异步日志,异步文件读写,异步 Mysql,异步 Redis,Mysql,Redis 连接池
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1549 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 192ms · UTC 18:10 · PVG 02:10 · LAX 10:10 · JFK 13:10
    ♥ Do have faith in what you're doing.