PHP PThread多线程编程之并发发送HTTP请求

前言

之前由于项目需求,采用了PHP 的pthread扩展编写异步并发程序。需求是这样的:单台服务器需要将每秒内上报的战报上传至服务器并保证上报成功率在99.9%以上,由于合作平台极其不稳定,大概率上报超时涉及重发。那么上报就必须使用异步队列,但是进程是很消耗系统资源,PHP本身是不支持线程的,最后采用了PHP 的pthread扩展进行多线程编程。(期间用过swoole所谓协程,测试数据差强人意;想过go重写,开发周期有限)

由于网上关于php多线程编程资料甚少(PHP本身的弱项),加上pthread缺少报错信息,导致调试难度。留下采坑过程,以供借鉴。

环境安装

由于LNMP模式安装的PHP非线程安装版本为php7.1, 为保持保持一致重编译线程版本也保持php7.1。官方提供7.1 pthread版本无法编译成功(Zend语法不兼容),感谢SKDSKL1提供的 https://github.com/sjdskl/pthreads-php7.1.git 提供的修改版本可成功编译安装。

git clone  https://github.com/sjdskl/pthreads-php7.1.git
cd pthreads-php7.1
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install
echo "extension=pthreads.so" >> /usr/local/php/etc/php.ini

/usr/local/php/bin/php Benchmark.php

由于LNMP开启线程安全是不值得的,所以同时存在2个版本的php(Thread Safety和No Thread Safety)。

pthread使用注意事项2

  1. 线程创建后,不能使用父线程的变量,诸如$GLOBALS或global等用法都无法操作父线程的全局变量

  2. 线程类的属性不能直接进行哈希表(数组)操作,如:

//这样是无效的
$this->var1["hello"] = "world"; 
//改为
$this->var1 = ["hello"=>"world"];

因为线程类属性的赋值是通过序列化实现的,其本质是存储了序列化数据。

  1. 不能调用父线程的redis、mysql等非标量的成员变量(引用类型的对象,涉及父线程的内存空间),如果是标量就可以。

  2. 最佳实践:为了安全起见,建议不要引用父线程的任意变量,用到的参数都通过Thread构造函数传入,可以把php线程当成轻量级的进程,不要做共享内存的操作。

线程类

<?php
/**
 * Created by PhpStorm.
 * User: liugaoyun
 * Date: 2018/8/4
 * Time: 上午11:51
 */

namespace console\threads;

class DemoThread extends \Thread
{
   
    public $dbConfig = null;    //db配置

    public $redisConfig = null; //redis配置

    public $debug = false;  //是否是debug模式


    public function __construct($dbConfig, $redisConfig, $debug = false)
    {
   
        $this->dbConfig = (array)$dbConfig;
        $this->redisConfig = (array)$redisConfig;
        $this->debug = $debug;
    }

    public function run() {
   
        //TODO:DB初始化
        $pdo = new \PDO($this->dbConfig['dsn'], $this->dbConfig["username"], $this->dbConfig["password"],array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));
        $pdo->exec("SET NAMES '" . $this->dbConfig["charset"] . "' COLLATE '" . $this->dbConfig["collation"] . "'");
        $pdo->exec("SET CHARACTER SET '" . $this->dbConfig["charset"] . "'");
        $pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ);

        //TODO:redis初始化
        $redis = new \Redis();
        $redis->pconnect($this->redisConfig
  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值