PHP高级编程之消息队列原理与实现方法详解(3)

这里只给出了少量测试与演示程序,如有疑问请到渎者群,或者公众号询问。

7. 多线程

上面消息队列 核心代码如下

$this->queue->consume(function($envelope, $queue) {
    $msg = $envelope->getBody();
    $result = $this->loader($msg);
    $queue->ack($envelope->getDeliveryTag());
});

这段代码生产环境使用了半年,发现效率比较低。有些业务场入队非常快,但处理起来所花的时间就比较长,容易出现队列堆积现象。

增加多线程可能更有效利用硬件资源,提高业务处理能力。代码如下

<?php
namespace framework;
require_once( __DIR__.'/autoload.class.php' );
class RabbitThread extends \Threaded {
    private $queue;
    public $classspath;
    protected $msg;
    public function __construct($queue, $logging, $msg) {
        $this->classspath = __DIR__.'/../queue';
        $this->msg = $msg;
        $this->logging = $logging;
        $this->queue = $queue;
    }
    public function run() {
        $speed = microtime(true);
        $result = $this->loader($this->msg);
        $this->logging->debug('Result: '. $result.' ');
        $this->logging->debug('Time: '. (microtime(true) - $speed) .'');
    }
    // private
    public function loader($msg = null){
        $protocol     = json_decode($msg,true);
        $namespace    = $protocol['Namespace'];
        $class         = $protocol['Class'];
        $method     = $protocol['Method'];
        $param         = $protocol['Param'];
        $result     = null;
        $classspath = $this->classspath.'/'.$this->queue.'/'.$namespace.'/'.strtolower($class) . '.class.php';
        if( is_file($classspath) ){
            require_once($classspath);
            //$class = ucfirst(substr($request_uri, strrpos($request_uri, '/')+1));
            if (class_exists($class)) {
                if(method_exists($class, $method)){
                    $obj = new $class;
                    if (!$param){
                        $tmp = $obj->$method();
                        $result = json_encode($tmp);
                        $this->logging->info($class.'->'.$method.'()');
                    }else{
                        $tmp = call_user_func_array(array($obj, $method), $param);
                        $result = (json_encode($tmp));
                        $this->logging->info($class.'->'.$method.'("'.implode('","', $param).'")');
                    }
                }else{
                    $this->logging->error('Object '. $class. '->' . $method. ' is not exist.');
                }
            }else{
                $msg = sprintf("Object is not exist. (%s)", $class);
                $this->logging->error($msg);
            }
        }else{
            $msg = sprintf("Cannot loading interface! (%s)", $classspath);
            $this->logging->error($msg);
        }
        return $result;
    }
}
class RabbitMQ {
    const loop = 10;
    protected $queue;
    protected $pool;
    public function __construct($queueName = '', $exchangeName = '', $routeKey = '') {
        $this->config = new \framework\Config('rabbitmq.ini');
        $this->logfile = __DIR__.'/../log/rabbitmq.%s.log';
        $this->logqueue = __DIR__.'/../log/queue.%s.log';
        $this->logging = new \framework\log\Logging($this->logfile, $debug=true);
 //.H:i:s
        $this->queueName    = $queueName;
        $this->exchangeName    = $exchangeName;
        $this->routeKey        = $routeKey;
        $this->pool = new \Pool($this->config->get('pool')['thread']);
    }
    public function main(){
        $connection = new \AMQPConnection($this->config->get('rabbitmq'));
        try {
            $connection->connect();
            if (!$connection->isConnected()) {
                $this->logging->exception("Cannot connect to the broker!"
.PHP_EOL);
            }
            $this->channel = new \AMQPChannel($connection);
            $this->exchange = new \AMQPExchange($this->channel);
            $this->exchange->setName($this->exchangeName);
            $this->exchange->setType(AMQP_EX_TYPE_DIRECT); //direct类型
            $this->exchange->setFlags(AMQP_DURABLE); //持久�?
            $this->exchange->declareExchange();
            $this->queue = new \AMQPQueue($this->channel);
            $this->queue->setName($this->queueName);
            $this->queue->setFlags(AMQP_DURABLE); //持久�?
            $this->queue->declareQueue();
            $this->queue->bind($this->exchangeName, $this->routeKey);
            $this->queue->consume(function($envelope, $queue) {
                $msg = $envelope->getBody();
                $this->logging->debug('Protocol: '.$msg.' ');
                //$result = $this->loader($msg);
                $this->pool->submit(new RabbitThread($this->queueName,
new \framework\log\Logging($this->logqueue, $debug=true), $msg));
                $queue->ack($envelope->getDeliveryTag());
            });
            $this->channel->qos(0,1);
        }
        catch(\AMQPConnectionException $e){
            $this->logging->exception($e->__toString());
        }
        catch(\Exception $e){
            $this->logging->exception($e->__toString());
            $connection->disconnect();
            $this->pool->shutdown();
        }
    }
    private function fault($tag, $msg){
        $this->logging->exception($msg);
        throw new \Exception($tag.': '.$msg);
    }
    public function __destruct() {
    }
}


      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/3758.html