【3工程開發】-php框架

php框架的功能通用的路由,autoload。服務端mysql封裝,日誌組件。前端的頁面渲染(smarty封裝個)。在工做時據說別的部門換框架性能提高,因此調研了下常見的框架,包含ci,laravel,yii,yaf,會介紹下功能,另外給出號稱最快框架yaf和經常使用yii和裸寫框架的性能差。另外想實現rpc併發,http通常用過multi_curl能夠,公司用的thrift沒有實現併發,因此研究了下php協程,curl_multi,swoole異步,rpc中併發實現,corotine等。php

經常使用php框架提供功能

  • ci http://codeigniter.org.cn/use...
    Route.
    autoload.載入文件正常controller 中load->helper(xx)。直接用xx
    log. db. hook.公共函數。
    代碼邏輯分層。
    ui抽象。模板。
  • laravel https://laravel-china.org/doc...
    路由
    中間件(前置後置)
    配置區分環境,本地和線上密碼不放其中
    數據庫 建立表,編輯,刪除,遷移,回滾,軟刪除和恢復(標記刪除位)。ORM鏈式操做
    依賴注入,依賴自動發現。html

    IOC 平時的if new 這種工廠模式,IoC模式看做工廠模式的昇華,之前在工廠模式裏寫死了的對象,IoC模式    改成配置XML文件,這就把工廠和要生成的對象二者隔離
    類(DatabaseQueue,queue,QueueContract),serviceprovider(外部調這個)=>bind(將類綁定到容器)。調用Queue::xx。依賴注入能夠直接調用$類->method。經過門面能夠類::method
    【https://www.cnblogs.com/shiwenhu/p/6882340.html】

    事件前端

    事件映射protected $listen = [
        'App\Events\OrderShipped' => [
            'App\Listeners\SendShipmentNotification',
        ],];
    寫事件OrderShipped,寫監聽SendShipmentNotification 能夠繼承隊列
    分發事件:public function ship($orderId)
        {
        order=Order::findOrFail(orderId);
        // 訂單的發貨邏輯...
        event(new OrderShipped($order));
        }

    隊列 ,redis,db, 廣播
    js監聽
    任務調度 只是cronmysql

  • yii https://www.yiichina.com/doc/...
    功能全面讀介於ci和laravel之間,前端支持功能豐富。組件和行爲是它的特點
    行爲laravel

    要定義行爲,經過繼承 yii\base\Behavior 。覆蓋其中的events方法,
    public function events() { 
        return [ 
            ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate', 
            ]; 
    } 
    public function beforeValidate($event) { 
        // 處理器方法邏輯 
    },
    附加行爲:lass User extends ActiveRecord { 
    public function behaviors() { 
        return [
            [ 
            'class' => MyBehavior::className(), 
            'prop1' => 'value1', 
            'prop2' => 'value2', 
        ]]}}或者attach組件就能夠使用行爲了。

    直觀感覺下
    clipboard.pnggit

  • yaf http://www.laruence.com/manua...
    php的一個擴展,由於是擴展,因此能夠常駐內存,不用每次加載框架了、實現了基本功能
    路由,
    插件能夠在幾個hook處調用,好比本身開發一個Log,在這些Hook的地方加入回調(https://github.com/akDevelope...
    autoload
    配置

yaf,cii,裸寫框架(autoload,路由)代碼和性能

性能比較

裸寫在CPU佔用方面和YAF相近,略高,在內存方面更節省。在吞吐量方面和YAF相近,略好。
CI框架會比YAF在CPU方面多耗費10%。吞吐量要差75%github

  • 吞吐
    裸寫優於yaf,yaf能夠比CI提高75%左右
    在php-fpm固定爲10個,看處理速度,所有打滿4000qps壓測。10s預熱,30s壓測
    咱們的框架最大吞吐量是2200/s,平均有970,一共處理了20萬
    ci的最大爲1850/s。可是會有502和504且有CPU爲0的時候,平均只有400,一共處理5萬左右,能夠看出ci在穩定狀況下最大的吞吐量能夠達到1600,共處理4萬左右
    yaf的最大吞吐量是2280/s。但平均只有670,因此一共處理7萬
  • CPU
    php-fpm開2048個,所有綁定到cpu1上, tsung壓直到打滿CPU,10秒預熱+30秒壓測
    yaf和咱們的框架能夠壓到600qps.CI到600直接CPU掉底了
    500時,咱們的框架略優於YAF.YAF相比於CI要節省至少10個點的CPU使用率
    300時,咱們的框架和YAF基本同樣,CI仍是要高出10個點。

代碼

  • yafweb

    index.php
    <?php
    define('APPLICATION_PATH', dirname(__FILE__));
    $performance = getrusage();
    $globalPerformStatics['cpu_time_start'] = $performance['ru_utime.tv_sec'] *1000000+ $performance['ru_utime.tv_usec']+$performance['ru_stime.tv_sec'] *1000000+$performance['ru_stime.tv_usec'];
    $application = new Yaf_Application( APPLICATION_PATH . "/conf/application.ini");
    $application->bootstrap()->run();
    $performance = getrusage();
    $globalPerformStatics['cpu_time_end'] = $performance['ru_utime.tv_sec'] *1000000+ $performance['ru_utime.tv_usec']+$performance['ru_stime.tv_sec'] *1000000+$performance['ru_stime.tv_usec'];
    var_dump($globalPerformStatics['cpu_time_end']-$globalPerformStatics['cpu_time_start']);
    ?>
     
    ————————————————————————————————
    Bootstrap.php
     
    <?php
    class Bootstrap extends Yaf_Bootstrap_Abstract {
        public function _initRoute(Yaf_Dispatcher $dispatcher) {
            $router = Yaf_Dispatcher::getInstance()->getRouter();
            $route = new Yaf_Route_Rewrite(
                'order/base/passenger/getinfo',
                array(
                    'controller' => 'Base_Passenger_Getinfo',
                    )
                );
            $router->addRoute('html1asdfd', $route);
        }
        public function _initView(Yaf_Dispatcher $dispatcher) {
            Yaf_Dispatcher::getInstance()->autoRender(false);
    }
    }
     
    ————————————————————————————————
    建立controller/Base/Passenger/Getinfo.php
     
    <?php
    class Base_Passenger_GetInfoController extends Yaf_Controller_Abstract {
    public function indexAction($name = "Stranger") {
        echo "hello";
        $orderId = $this->getRequest()->getQuery("order_id");
         $model = new SampleModel();
                $orderInfo = $model->selectSample($orderId);
        var_dump($orderInfo);
        return TRUE;
    }
    }
     
    ————————————————————————————————
    建立Model
     
    <?php
    /**
     * @name SampleModel
     * @desc sample數據獲取類, 能夠訪問數據庫,文件,其它系統等
     * @author */
      class SampleModel {
        public function __construct() {
        }
        public function selectSample($id) {
                    $a = $id / 5.314; // 取反正切 0-5.314的變化區間
                            $b = 1000 / 1.520837931073;
                            return intval((100 / $a) * $b);
                                }
        public function insertSample($arrInfo) {
            return true;
        }
      }
  • 裸寫redis

    index.php
    <?php
    define('FRAMEPATH', '/home/project/phputil/');
    define('APPPATH', '/home/project/order/');
    $performance = getrusage();echo 1;
    $globalPerformStatics['cpu_time_start'] = $performance['ru_utime.tv_sec'] *1000000+ $performance['ru_utime.tv_usec']+$performance['ru_stime.tv_sec'] *1000000+$performance['ru_stime.tv_usec'];
    $appNameSpace = 'Project\Order';
    $_GET = array_merge($_GET, $_POST);//fix Android端把$_GET改爲$_POST問題
    require_once(FRAMEPATH . '/autoload/autoloader.php');
    $loader = Project\Autoload\Autoloader::getLoader();
    $loader->addPsr4('Project\Order\\', APPPATH);
    require_once(FRAMEPATH . '/framework.php');
    $performance = getrusage();
    $globalPerformStatics['cpu_time_end'] = $performance['ru_utime.tv_sec'] *1000000+ $performance['ru_utime.tv_usec']+$performance['ru_stime.tv_sec'] *1000000+$performance['ru_stime.tv_usec'];
    var_dump($globalPerformStatics['cpu_time_end']-$globalPerformStatics['cpu_time_start']);
    ?>
     
    ————————————————————————————————
    config/route.php
    <?php
    namespace Project\Order\Config;
    class Route
    {
            public static $routes = array(
                        'order/(.+)' => '$1',
                    );
    }
     
    ————————————————————————————————
    helper/order.php
    <?php
    namespace Project\Order\Helper;
    class Order{
        public static function selectSample($id) {
              $a = $id / 5.314; // 取反正切 0-5.314的變化區間
              $b = 1000 / 1.520837931073;
              return intval((100 / $a) * $b);
        }
    }
     
    ————————————————————————————————
    phputil
     
    <?php
    $loader->addPsr4('Project\Framework\\', FRAMEPATH . '');
    //全局變量定義(暫時作法,限制性使用)
    $__uid   = 0;
    $_startTime = '';
    $_redisCount = 0;
    $_mysqlCount = 0;
    $_httpRpcCount = 0;
    $_thriftRpcCount = 0;
    try {
        $params = array('get' => $_GET, 'post' => $_POST);
        $routerConfigPath = $appNameSpace . '\Config\Route';
        $routerConfig = array();
        $errorPageConfig = false;
        if(class_exists($routerConfigPath)){
            if(!empty($routerConfigPath::$routes) && is_array($routerConfigPath::$routes)){
                $routerConfig = $routerConfigPath::$routes;
            }
            if(!empty($routerConfigPath::$showErrorPage)){
                $errorPageConfig = $routerConfigPath::$showErrorPage;
            }
        }
        $_startTime = microtime(true);
        $router = new \Project\Framework\Base\Router($_SERVER['REQUEST_URI'], $routerConfig,$errorPageConfig);
        $router->setRoute();
        $router->run($params);
    } catch (\InvalidArgumentException $ex) {
        $errNo = -1;
        $errMsg = strlen($ex->getMessage()) ? $ex->getMessage() : 'system error';
      var_dump(array('errno' => $errNo, 'errmsg' => $errMsg));
    } catch (\Exception $ex) {
        $errNo = $ex->getCode();
        $errMsg = $ex->getMessage();
     var_dump(array('errno' => $errNo, 'errmsg' => $errMsg));
    }
  • cisql

    config/route.php
    CI多級目錄支持須要本身開發,粗暴的把路由直接打到welcome.php
    $route['(.+)'] = 'welcome';
     
    ————————————————————————————————
    controller/Welcome.php
     
    <?php
    class Welcome extends CI_Controller {
        public function __construct()
        {
            parent::__construct();
            $this->load->model('SampleModel');
        }
        public function index()
        {
    echo "hello";
    $orderId=$this->input->get('order_id');
            $orderInfo = $this->SampleModel->selectSample($orderId);
     
    var_dump($orderInfo);
    return 1;
    }
    }
     
    ————————————————————————————————
    model/SampleModel.php
     
    <?php
    class SampleModel extends CI_Model {
    public function selectSample($id) {
                    $a = $id / 5.314; // 取反正切 0-5.314的變化區間
                            $b = 1000 / 1.520837931073;
                            return intval((100 / $a) * $b);
                                }
        public function insertSample($arrInfo) {
            return true;
        }
    }

php異步rpc

php協程

php爲什麼不用多線程:

pthreads v3 is restricted to operating in CLI only: I have spent many years trying to explain that threads in a web server just don't make sense, after 1,111 commits to pthreads I have realised that, my advice is going unheeded.
So I'm promoting the advice to hard and fast fact: you can't use pthreads safely and sensibly anywhere but CLI.
Thanks for listening ;)

curl_mutli

設爲非阻塞的socket,調用libcurl的方法。也是select後執行,跟咱們php協程處理方式差很少
curl_multi_init
curl_multi_add_handle
curl_multi_select
select有結果後curl_multi_perform // multi_runsingle.一個一個進行,狀態流轉,從任何一個狀態均可以繼續執行
當select結束後curl_multi_info_read
curl_multi_remove_handle,curl_multi_cleanup

swoole框架異步和corotine實現

swoole:https://wiki.swoole.com/wiki/...
協程原理:跳堆棧的原理
異步:客戶端/mysql/redis/http等。這些只能在cli下調用。不能在fpm中, 異步就是設爲非阻塞的socket, 而後設置回調。epoll。一個進程就好了。

自開發併發rpc

http協議封裝libcurl.其餘協議 狀態機+epoll

workerman-thrift

須要分開提供發送和讀取兩個接口。對發送和讀取兩個步驟實現異步。先發送一批再讀取,不是發完了等待接收再下一個。

相關文章
相關標籤/搜索