frozenway
V2EX  ›  PHP

2020 年了,现在最简单的 PHP 执行异步任务的方式是什么,不要框架,尽量十几二十行 PHP 代码能搞定?

  •  
  •   frozenway · Jun 12, 2020 · 8553 views
    This topic created in 2338 days ago, the information mentioned may be changed or developed.

    想在这台服务器(国内)php 保存某些数据后,去更新另外一台服务器(国外)的文件缓存,如果是同步更新,保存数据的响应结果会太慢太卡,想着异步去做。要求尽量简单,不想左一个框架右一个框架,不用 redis,memkache 等,因为开启这些扩展需要编译 php,麻烦

    44 replies  •  2020-06-23 15:31:53 +08:00
    luyaolu
    luyaolu
    Jun 12, 2020
    1
    接口请求另一个接口 我想到最简单的
    CODEWEA
    CODEWEA
    Jun 12, 2020
    2
    搜索关键词:linux 进程通信
    yakumo520
    yakumo520
    Jun 12, 2020
    3
    那你干脆不用 php 吧,直接 linux 协程
    qiayue
    qiayue
    Jun 12, 2020
    4
    每一步一个 php 文件,假设 3 步,那就 3 个文件
    step1.php 执行完之后,跳转到 step2.php ,执行完之后再跳转到 step3.php ,执行完之后跳回 step1.php
    每次 step1.php 来判断是否有新的任务需要执行。
    注意跳转不要用 header location 形式,而是用 html meta refresh 形式,延迟 1 秒跳转

    然后你就开浏览器让他不断自动执行就行。
    frozenway
    frozenway
    OP
    Jun 12, 2020
    5
    @qiayue 这个方法不错
    richangfan
    richangfan
    Jun 12, 2020 via Android
    6
    加个定时任务
    TORYOI
    TORYOI
    Jun 12, 2020
    7
    @qiayue 我以前用过这种方式,只是感觉好别扭
    mokeyjay
    mokeyjay
    Jun 12, 2020❤️1
    8
    crontab -e
    php job.php
    keepeye
    keepeye
    Jun 12, 2020
    9
    单独写个服务,提供一个任务接口,调用接口的时候 fork 子进程处理,直接返回不用等待处理结果
    whahugao
    whahugao
    Jun 12, 2020
    10
    用 popen 另外起一个 php 进程去执行异步任务呗
    ben1024
    ben1024
    Jun 12, 2020
    11
    要是数据库可以用 canal
    纯文件挂文件流传输,一个点开,一个点请求
    yuzo555
    yuzo555
    Jun 12, 2020
    12
    如果只是这个简单的需求,那么 PHP 是可以先响应然后继续执行的呀。

    https://stackoverflow.com/questions/15273570/continue-processing-php-after-sending-http-response
    Ech0o0
    Ech0o0
    Jun 12, 2020
    13
    ```php
    <?php

    set_time_limit(30);
    ignore_user_abort(false);

    header("Content-Length: 0");
    header("Connection: Close");
    echo str_pad('', ini_get('output_buffering'));
    ob_end_flush();
    ob_flush();
    flush();

    //耗时任务
    sleep(10);
    file_put_contents('test.log', date('Y-m-d H:i:s'), FILE_APPEND);
    ```

    ```php
    <?php

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, 'http://127.0.0.1/async.php');
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_exec($curl);
    curl_close($curl);

    echo '结束了';
    ```

    有局限性,最好还是用队列吧
    explore365
    explore365
    Jun 12, 2020
    14
    还是用一下框架吧,workerman,比较简单一些
    frozenway
    frozenway
    OP
    Jun 12, 2020
    15
    @yuzo555 这个长见识了
    luckyrayyy
    luckyrayyy
    Jun 12, 2020
    16
    crontab 系统自带啊
    I2E
    I2E
    Jun 12, 2020
    17
    尝试过,没搞出来,应该没法光靠 php 。说 sleep 的是认真的吗?
    I2E
    I2E
    Jun 12, 2020
    18
    php 只能启多个进程去搞
    I2E
    I2E
    Jun 12, 2020
    19
    我们现在通过这种方式实现异步任务。通过 pm2 启动一个 rabbitmq 死信队列,设置到期时间。一旦到期就会执行指定任务
    AngryPanda
    AngryPanda
    Jun 12, 2020
    20
    @I2E fastcgi_finish_request
    caola
    caola
    Jun 12, 2020
    21
    swoole,编译只是一条命令而已 🐶
    GG668v26Fd55CP5W
    GG668v26Fd55CP5W
    Jun 12, 2020
    22
    beanstalkd 简单粗暴
    Tokin
    Tokin
    Jun 12, 2020
    23
    记得当时弄的一个简单的队列,后来改用 node 了。
    dadmin
    dadmin
    Jun 12, 2020
    24
    国外服务器更新缓存功能写成接口 (需要设置 set_time_out(0); ignore_user_abort(true);)
    国内服务器通过 curl 请求国外更新缓存接口 并设置执行超时时间
    kaneg
    kaneg
    Jun 12, 2020 via iPhone
    26
    crontab 就是干这个活的
    Enivel
    Enivel
    PRO
    Jun 13, 2020
    27
    fastcgi_finish_request 正解啊 应该是最简单方式了一行代码搞定.
    edk24
    edk24
    Jun 13, 2020
    28
    RabbitMQ, 最近刚用上这个队列功能处理视频转码.
    http://aili.edk24.com/1754293

    也许可以试一下, 消费者和生产者连接同一个服务, 生产者投递任务即时响应返回, 消费者在另一个服务器收到任务对它进行处理


    同步文件可以用 scp 之类的命令. 个人不精的建议. 也就 docker 运行个 Rabbitmq, 其他还真是几行代码
    edk24
    edk24
    Jun 13, 2020
    29
    或者 swoole 有异步任务
    PHPJit
    PHPJit
    Jun 13, 2020 via iPhone
    30
    fastcgi_finish_request
    raysonlu
    raysonlu
    Jun 13, 2020
    31
    “开启这些扩展需要编译 php,麻烦” 。。。???
    yincrow
    yincrow
    Jun 13, 2020
    32
    swoole 的 worker 可以满足
    jay4497
    jay4497
    Jun 13, 2020
    33
    曾经用 curl 做过类似的,就是发 curl 请求,设置不需要返回结果,然后再设个一秒的超时时间,效果就是程序到这会停一秒,然后就继续执行了,不会等待那边处理完成返回结果。。。
    pandait
    pandait
    Jun 13, 2020
    34
    用鸟哥的那个 blog 的 fsockopen
    realpg
    realpg
    Jun 13, 2020
    35
    @frozenway #5 PHP 海量数据下 删除数据、生成数据防卡死的标准操作 自刷新也可以
    ViggoSite
    ViggoSite
    Jun 13, 2020
    36
    系统定时任务 或者 workman,简单又方便
    encro
    encro
    Jun 13, 2020
    37
    dnf or apt install php-redist 还好吧
    workerman swoole Gearman 也还好吧
    phpize 也麻烦?
    blurh11E27
    blurh11E27
    Jun 13, 2020
    38
    redis 发布订阅
    go522000
    go522000
    Jun 13, 2020
    39
    以前用过 fsockopen 做异步请求,挺好用,你可以搜索相关文章参考一下。
    yincrow
    yincrow
    Jun 13, 2020
    40
    @yincrow 我看了下 swoole 的文档,coroutine 和 process
    sagaxu
    sagaxu
    Jun 13, 2020 via Android
    41
    “报告长官,有人在诋毁和攻击 PHP”
    “他都胡说八道些什么?”
    “他竟然把 PHP 特性和技巧讲了一遍”
    msg7086
    msg7086
    Jun 13, 2020
    42
    建议招个运维,解决一下开 PHP 扩展要编译 PHP 的问题。
    cbasil
    cbasil
    Jun 15, 2020
    43
    最简单的使用 fsockopen
    $fp = fsockopen ( $hostname, $port, $errno, $errstr, 600 );
    stream_set_blocking ( $fp, 0 ); //开启非阻塞模式
    fputs ( $fp, "GET " . $url . "\r\n" );
    fclose ( $fp );
    jeepc
    jeepc
    Jun 23, 2020❤️1
    44
    <?php

    namespace app\util;


    class HttpUtils
    {


    /**
    * 异步执行
    * @param $host
    * @param $path
    * @param array $param
    * @return false|int|string
    */
    public static function requestAsync($host, $path, $param = array())
    {

    $query = isset($param) ? http_build_query($param) : '';

    $fp = @fsockopen($host);

    if (!$fp) {
    logError('连接失败');
    return 'connection error';
    }

    stream_set_blocking($fp, 0); //非阻塞
    stream_set_timeout($fp, 1);//响应超时时间( S )
    $out = "POST " . $path . " HTTP/1.1\r\n";
    $out .= "host:" . $host . "\r\n";
    $out .= "content-length:" . strlen($query) . "\r\n";
    $out .= "content-type:application/x-www-form-urlencoded\r\n";
    $out .= "connection:close\r\n\r\n";
    $out .= $query;

    $result = @fputs($fp, $out);

    @fclose($fp);
    return $result;

    }

    }

    <?php

    namespace app\api\controller;

    use app\util\HttpUtils;
    use think\Controller;
    use think\facade\Log;

    class Test extends Controller
    {
    public function test(){
    sleep(5);
    Log::record(1111);
    }

    public function testAsync(){

    HttpUtils::requestAsync($_SERVER['HTTP_HOST'],'/api/test/test');
    dump('return');
    }

    }

    仅供参考
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2193 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 114ms · UTC 11:27 · PVG 19:27 · LAX 03:27 · JFK 06:27
    ♥ Do have faith in what you're doing.