0

0

PHP CLI 多进程执行启动脚本

PHP中文网

PHP中文网

发布时间:2016-05-26 08:20:33

|

1802人浏览过

|

来源于php中文网

原创

1.截图

5.jpg

2.bat.php

触发式加载精美特效企业网站源码1.0.0
触发式加载精美特效企业网站源码1.0.0

触发式加载精美特效企业网站源码使用jquery实现了很多精美的触发式加载特效,网站首页在随着访客的滚动条滚动过程中会出现很多触发式加载的特殊效果,让这个网站的风格瞬间显得非常的高大上,让你的企业品牌在访客心中留下更深的影响。当然,我们在使用jquery特效的同时也要注意程序对搜索引擎的友好型,所以这一点儿作者也有考虑到,已经尽可能的对js和css脚本进行精简和优化,尽可能的加快网站加载速度,同时也

下载
#!/usr/bin/env php
 159);
}
 
function b($line){
    do{
        bat::notify("我是显示传递的参数 \$line = $line");
        usleep(500000);
    }while(mt_rand(100, 999) > 359);
}
 
function c(){
    global $x;
    bat::notify("多个任务之间的初始变量值不受影响, \$x = $x");
    bat::notify("我是暂停 9 秒时间测试");
    sleep(9);
    bat::notify("我是出错代码 5 测试");
    exit(5);
}
 
 * ?>
 */
 
/** 确保这个脚本只能运行在 SHELL 中 */
if(substr(php_sapi_name(), 0, 3) !== 'cli'){
    die("This Programe can only be run in CLI mode.\n");
}
 
if(!is_callable('pcntl_fork') || !is_callable('msg_send')){
    bat::message("本程序需要 pcntl, sysvmsg 扩展,但您的系统没有安装!", 2);
    exit(5);
}
 
class bat{
    static private
            $max = 3,
            $total = 0,
            $running = 0,
            $failure = 0,
            $finished = 0,
            $tasks = array(),
            $msg, $msgs = array(),
            $logfile = "/tmp/bat.php.log",
            $childs, $get, $parent,
            $start, $split;
 
    static function main(){
        $i = 1;
        $files = array();
        if($_SERVER["argc"] > 1){
            while($i < $_SERVER["argc"]){
                switch($_SERVER["argv"][$i++]){
                    case "?":
                    case "/?":
                    case "-?":
                    case "-h":
                    case "--help":
                        self::usage();
                    case "-f":
                    case "--file":
                        $file = $_SERVER["argv"][$i++];
                        if(is_readable($file)){
                            $files[] = $file;
                            continue;
                        }
                        if(is_null($file)){
                            self::message("缺少脚本参数", 1);
                            help(1);
                        }else{
                            self::message("脚本 $file 不在在或不可访问", 2);
                            exit(4);
                        }
                    case "-m":
                    case "--max":
                        if(self::$max = $_SERVER["argv"][$i++]){
                            self::$max = intval(self::$max);
                            if(self::$max >= 1){
                                continue;
                            }
                            self::message("进程数量应为正整数", 2);
                            exit(8);
                        }
                        self::message("未指定进程数量", 2);
                        exit(7);
                    case "-l":
                    case "--log":
                    case "--logfile":
                        if(self::$logfile = $_SERVER["argv"][$i++]){
                            if(is_dir(self::$logfile)){
                                self::$logfile .= "/bat.php.log";
                            }
                            if(is_file(self::$logfile)){
                                if(is_writable(self::$logfile)){
                                    continue;
                                }
                            }else{
                                if(is_writable(dirname(self::$logfile))){
                                    continue;
                                }
                            }
                            self::message("日志目录不可写", 2);
                            exit(9);
                        }
                    case "-v":
                    case "--version":
                        exit(self::version());
                    default :
                        $file = $_SERVER["argv"][$i - 1];
                        if(is_readable($file)){
                            $files[] = $file;
                            continue;
                        }
                        self::message("脚本 $file 不在在或不可访问", 2);
                        exit(4);
                }
            }
 
            set_time_limit(0);
            error_reporting(8106 & E_ALL);
            ini_set('display_errors', 'Off');
            set_error_handler(array(__CLASS__, 'error'), E_ALL);
            set_exception_handler(array(__CLASS__, 'exception'));
            register_shutdown_function(array(__CLASS__, 'shutdown'));
 
            self::$start = time();
            self::$split = str_repeat('=', 512);
            self::$parent = msg_get_queue(getmypid());
 
            foreach($files as $file){
                self::inc($file);
            }
 
            self::end();
            exit;
        }
 
        self::usage();
    }
 
    static function run($fun, $arg = null){
        if(is_callable($fun)){
            self::$tasks[] = array($fun, $arg);
        }else{
            throw new Exception("不是函数或不可调用", 9);
        }
    }
 
    static function start(){
        self::$total = count(self::$tasks);
        foreach(self::$tasks as $fun_arg){
            if(self::$max < ++self::$running){
                self::run_wait();
            }elseif(self::$running == 1){
                # 清屏并设置光标到第一行
                $x = intval(`tput lines`);
                echo str_repeat("\n", $x -1);
                self::flush('程序开始执行...', 1);
            }
            if($cid = pcntl_fork()){
                if($cid < 0){
                    throw new Exception("创建进程失败", 3);
                }
                self::$childs[$cid] = msg_get_queue($cid);
            }else{
                ob_start();
                self::$tasks = array();
                self::$get = msg_get_queue(getmypid());
                self::$msg = sprintf("%-6d", getmypid());
                msg_send(self::$parent, 1, getmypid(), false);
                call_user_func($fun_arg[0], $fun_arg[1]);
                exit;
            }
        }
        while(self::$running) self::run_wait();
        self::$tasks = array();
    }
 
    static private function run_wait(){
        $nomsg_interval = time();
label_wait:
        if(msg_receive(self::$parent, 0, $typ, 8192, $msg, false, MSG_NOERROR | MSG_IPC_NOWAIT)){
            if($typ != 3){
                if($typ == 1){
                    $msg = sprintf("%-6d%s %s", $msg, date("H:i:s"), '进程启动');
                }elseif($typ == 4){
label_child_exit:
                    unset(self::$childs[pcntl_waitpid($msg, &$status)]);
                    if(!pcntl_wifexited($status) || pcntl_wexitstatus($status)){
                        $msg = sprintf("%-6d%s %s", $msg, date("H:i:s"), '进程异常退出');
                        if(pcntl_wifexited($status)){
                            $msg .= ',错误代码:' . pcntl_wexitstatus($status);
                        }
                        self::$failure++;
                    }else{
                        $msg = sprintf("%-6d%s %s", $msg, date("H:i:s"), '进程执行完毕');
                        self::$finished++;
                    }
                    self::flush($msg, $nomsg_interval);
                    self::$running--;
                    return;
                }else{
                    goto label_wait;
                }
            }
            $nomsg_interval = time();
            self::flush($msg, $nomsg_interval);
        }else{
            if($nomsg_interval != time()){
                foreach(self::$childs as $msg => $t){
                    if(!msg_queue_exists($msg)){
                        goto label_child_exit;
                    }
                }
                echo "\33[0;0H"; $lines = intval(`tput lines`);
                echo "\33[K运行时长:", self::run_time(), ' ', date("Y-m-d H:i:s", self::$start), ' - ', date("Y-m-d H:i:s"), "\33[$lines;0H";
            }
            usleep(100000);
        }
        goto label_wait;
    }
 
    static function notify($msg){
        msg_send(self::$parent, 3, self::$msg . date("H:i:s ") . $msg, false);
    }
 
    static function message($msg, $code = 0){
        switch($code){
        case 0:
            echo "\33[37m提示:\33[0m", $msg, "\n";
            break;
        case 1:
            echo "\33[33m警告:\33[0m", $msg, "\n";
            break;
        case 2:
            echo "\33[31m错误:\33[0m", $msg, "\n";
            break;
        }
    }
 
    static function confirm($msg = "确定要继续执行"){
        echo $msg, "(yes/no)?: "; # 暂这样
        return "yes\n" == fgets(STDIN);
    }
 
    static function help($code = 0){
        echo "\n请使用 $_ENV[_] --help 查看帮助!\n";
        $code && exit($code);
    }
 
    static function usage(){
        $bat = __CLASS__;
 
        echo ""
        , "Usage:\n"
        , " $_ENV[_] [options] [-f | --file] \n"
        , "Options:\n"
        , " -h | --help     显示本帮助信息\n"
        , " -v | --version      查看程序版本信息\n"
        , "\n"
        , " -m | --max   同时执行进程数量,默认 ", self::$max, " 个\n"
        , " -l | --log  错误记录日志文件,默认 ", self::$logfile, "\n"
        , "Information:\n"
        , " 脚本中调用 $bat::run(fun[, arg]) 来添加任务\n"
        , " fun 为要执行的函数名;arg 为传递给这个函数的参数,可省\n"
        , "\n"
        , " 脚本中调用 $bat::start() 来启动子进程执行上面添加的任务\n"
        , " 在子进程中,通过调用 $bat::notify(msg) 发送要显示的信息给父进程\n"
        , " 在子进程中,程序执行发生错误,要让主进程统计为失败需用 exit(num) 非零返回\n"
        ;
        exit;
    }
 
    static function version(){
        return "Version: 0.1 by huye\n";
    }
 
    static private function inc($file){
        include $file;
    }
 
    static private function end(){
        $cols = intval(`tput cols`);
        $lines = intval(`tput lines`);
 
        if(self::$total){
            self::flush("执行完毕.", 1);
            echo "\33[$lines;{$cols}H\33[1C\n\n";
        }
 
        if(is_file(self::$logfile))echo "\33[K发生错误:", self::$logfile, "\n";
        echo "\33[K运行时长:", self::run_time(), ' ', date("Y-m-d H:i:s", self::$start), ' - ', date("Y-m-d H:i:s"), "\n";
        echo "\33[K执行完毕:已完成任务 ", self::$finished, " 个", self::$failure ? ",失败 " . self::$failure . " 个" : "", self::$total ? "(共 " . self::$total . " 个)" : "", "。\n";
    }
 
    static private function flush($msg, $time){
        $cols = intval(`tput cols`);
        $lines = intval(`tput lines`);
        if($msg){
            $_max = $cols;
            foreach(explode("\n", $msg) as $msg){
                if($cols < strlen($msg)){# ascii utf8 ascii utf8 ascii ...
                    $tmp = preg_split("#((?:[\xe0-\xef][\x80-\xbf]{2})+)#", $msg, 0, PREG_SPLIT_DELIM_CAPTURE);
                    for($i = 0, $l = count($tmp); $i < $l;){
                        $x = strlen($z = $tmp[$i]);
                        if($_max > $x){
                            $_max -= $x;
                            if(++$i >= $l)break;
                            $x = strlen($z = $tmp[$i]) / 3 * 2;
                            if($_max > $x){
                                $_max -= $x;
                                $i++; continue;
                            }elseif($_max < $x){
                                $_max = floor($_max / 2) * 3;
                                $msg = array_slice($tmp, $i -1);
                                $msg[0] = '';
                                $msg[1] = substr($z, $_max);
                                $tmp[$i] = substr($z, 0, $_max);
                            }else{
                                $msg = array_slice($tmp, $i + 1);
                            }
                        }elseif($_max < $x){
                            $msg = array_slice($tmp, $i);
                            $msg[0] = substr($z, $_max);
                            $tmp[$i] = substr($z, 0, $_max);
                        }else{
                            $msg = array_slice($tmp, $i);
                            $msg[0] = '';
                        }
                        if(++$i < $l){
                            array_splice($tmp, $i);
                        }
                        if(isset($msg[1])){
                            self::$msgs[] = implode("", $tmp);
                            $msg[0] = "               " . $msg[0];
                            $i = 0; $l = count($msg); $tmp = $msg; $_max = $cols;
                        }elseif(isset($msg[0]) && strlen($msg[0])){
                            self::$msgs[] = implode("", $tmp);
                            if($cols - 15 < strlen($msg[0])){
                                foreach(str_split($msg[0], $cols - 15) as $tmp){
                                    $tmp = "               " . $tmp;
                                    if($cols == strlen($tmp)){
                                        self::$msgs[] = $tmp;
                                    }else{
                                        $tmp = array($tmp);
                                        break;
                                    }
                                }
                            }else{
                                $tmp = array("               " . $msg[0]);
                            }
                            break;
                        }else{
                            break;
                        }
                    }
                    self::$msgs[] = implode("", $tmp);
                }else{
                    self::$msgs[] = $msg;
                }
            }
        }else{
            self::$msgs[] = $msg;
        }
 
        static $last_time = 0;
        if($last_time == $time)return true;
        $last_time = $time; # 防止在远程 ssh 的时候刷屏死掉
 
        echo "\33[0;0H";
#       echo "\33[K程序信息:", self::version();
        echo "\33[K运行时长:", self::run_time(), ' ', date("Y-m-d H:i:s", self::$start), ' - ', date("Y-m-d H:i:s"), "\n";
 
        if($lines < 5){
            if($lines < 3) return;
        }else{
            echo $split = substr(self::$split, 0, $cols), "\n";
 
            if(($_max = count(self::$msgs) + 4) > $lines){
                array_splice(self::$msgs, 0, $_max - $lines);
            }elseif($lines > $_max){
                $split = str_repeat("\n\33[K", $lines - $_max) . $split;
            }
 
            echo "\33[K", implode("\n\33[K", self::$msgs), "\n", $split, "\n";
        }
 
        $msg = "已完成任务 " . self::$finished . " 个";
        if(self::$failure) $msg .= ",失败 " . self::$failure . " 个";
        if(self::$total) $msg .= "(共 " . self::$total . " 个)";
        echo str_repeat(' ', $cols - strlen(preg_replace("#[\xe0-\xef][\x80-\xbf]{2}#", "**", $msg))), $msg, "\33[$lines;0H";
    }
 
    static function run_time(){
        $consume = time()
                 - self::$start;
 
        $str = "";
        if($consume >= 86400){
            $str = floor($consume / 86400) . "天";
            $consume = $consume % 86400;
            $zero = true;
        }
        if($consume >= 3600){
            $str .= floor($consume / 3600) . "时";
            $consume = $consume % 3600;
            $zero = true;
        }elseif($consume > 0 && isset($zero)){
            unset($zero);
            $str .= "零";
        }
        if($consume >= 60){
            $str .= floor($consume / 60) . "分";
            $consume = $consume % 60;
            $zero = true;
        }elseif($consume > 0 && isset($zero)){
            unset($zero);
            $str .= "零";
        }
        if($consume > 0){
            $str .= $consume . "秒";
        }elseif($str == ""){
            $str = "0秒";
        }
 
        return $str;
    }
 
    static function error($no, $err, $file, $line){
        if(error_reporting()){
            $log = $no & 1032 ? 'M' : ($no & 514 ? 'W' : ($no & 2048 ? 'M' : 'E'));
            $log = "[" . date("m-d H:i:s") . "] $log $line $file $err\n";
            file_put_contents(self::$logfile, $log, FILE_APPEND);
        }
    }
 
    static function shutdown(){
        if($last = error_get_last() and 85 & $last['type']){
            self::error($last['type'], $last['message'], $last['file'], $last['line']);
            self::$get || self::end();
        }
        if(self::$get){
            msg_send(self::$parent, 4, getmypid(), false); # 通知父进程结束
            self::$parent = self::$get; # 同时也防止上一行通知失败
            ob_end_clean();
        }
        msg_remove_queue(self::$parent);
    }
 
    static function exception($e){
        self::error($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine());
        exit($e->getCode());
    }
}
 
bat::main();
PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

50

2026.02.06

快手网页版入口与电脑端使用指南 快手官方短视频观看入口
快手网页版入口与电脑端使用指南 快手官方短视频观看入口

本专题汇总了快手网页版的最新入口地址和电脑版使用方法,详细提供快手官网直接访问链接、网页端操作教程,以及如何无需下载安装直接观看短视频的方式,帮助用户轻松浏览和观看快手短视频内容。

8

2026.02.06

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

7

2026.02.06

Python 微服务架构与 FastAPI 框架
Python 微服务架构与 FastAPI 框架

本专题系统讲解 Python 微服务架构设计与 FastAPI 框架应用,涵盖 FastAPI 的快速开发、路由与依赖注入、数据模型验证、API 文档自动生成、OAuth2 与 JWT 身份验证、异步支持、部署与扩展等。通过实际案例,帮助学习者掌握 使用 FastAPI 构建高效、可扩展的微服务应用,提高服务响应速度与系统可维护性。

4

2026.02.06

JavaScript 异步编程与事件驱动架构
JavaScript 异步编程与事件驱动架构

本专题深入讲解 JavaScript 异步编程与事件驱动架构,涵盖 Promise、async/await、事件循环机制、回调函数、任务队列与微任务队列、以及如何设计高效的异步应用架构。通过多个实际示例,帮助开发者掌握 如何处理复杂异步操作,并利用事件驱动设计模式构建高效、响应式应用。

4

2026.02.06

java连接字符串方法汇总
java连接字符串方法汇总

本专题整合了java连接字符串教程合集,阅读专题下面的文章了解更多详细操作。

25

2026.02.05

java中fail含义
java中fail含义

本专题整合了java中fail的含义、作用相关内容,阅读专题下面的文章了解更多详细内容。

28

2026.02.05

控制反转和依赖注入区别
控制反转和依赖注入区别

本专题整合了控制反转和依赖注入区别、解释、实现方法相关内容。阅读专题下面的文章了解更多详细教程。

19

2026.02.05

钉钉脑图插图教程合集
钉钉脑图插图教程合集

本专题整合了钉钉脑图怎么插入图片、钉钉脑图怎么用相关教程,阅读专题下面的文章了解更多详细内容。

60

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Swoft2.x速学之http api篇课程
Swoft2.x速学之http api篇课程

共16课时 | 1.0万人学习

韩顺平 2016年 最新PHP基础视频教程
韩顺平 2016年 最新PHP基础视频教程

共47课时 | 10.2万人学习

从0开始进入PHP的世界
从0开始进入PHP的世界

共89课时 | 12.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号