背景
由于一直处于一种瓶颈,不知道该学一些什么。就玩起多线程了。之前就有了解过多线程,也听过PHP的多线程是非常不友好的,那么我就要研究一下其弱势与优势。
认识线程
线程是一条执行路径,是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。
注意:线程间共享进程的所有资源
官方注意的点
静态成员: 当创建新的线程上下文(Thread 或 Worker 对象)的时候,静态成员会被拷贝到新的上下文中。出于安全考虑,资源类型以及包含内部状态的对象类型的静态成员会被置空。 实际上这个特性实现了类似线程本地存储的功能。举例说明,假设某个类拥有包含数据库连接信息以及数据库连接对象静态成员, 那么当新的线程上下文启动的时候,仅有数据库连接信息会被复制到新上下文中,而数据库连接对象并不会被复制。 所以,需要在新的上下文中根据复制过来的数据库连接基本信息来初始化数据库连接对象,新创建的数据库连接对象是独立的, 不影响在原上下文中的数据库连接对象。
** 这句话是什么意思?意思就是:我只保留静态的东西,你们什么对象,资源,什么的都会被我清空。我这是为了安全着想。
看到这里我就感觉到其实这里的多线程只有静态成员会被保存下来,其他变量和对象都不会被保存下来。那么如果运用在框架里面的东西,一般都是面向对象的,但是新建线程他不被保留,需要重新去实例,这就对PHP很不友好了,毕竟框架里面的东西都已经集成了,如果全部都被置空,那么很多东西都需要自己重新编写,这就是PHP和其他的线程异同的地方。
运行环境
操作系统:window
PHP:5.6
框架:thinkphp
数据库:mysql
执行流程
public function spthread(){//静态成员// 当创建新的线程上下文(Thread 或 Worker 对象)的时候,静态成员会被拷贝到新的上下文中。//出于安全考虑,资源类型以及包含内部状态的对象类型的静态成员会被置空//ThreadBase::$database = Db::connect(); //被置空ThreadBase::$arr = [\'statu\'=>1111];//被置空ThreadBase::$noraml = 123; //有值//数据存储: 一般来说,任何可以序列化的数据类型都可以作为 Threaded 对象的属性,它可以从持有该对象引用的任何线程上下文读/写ThreadBase::$database = serialize(Db::getConfig()); //有值$my = new \\app\\logic\\Distrubut();$my->start();//开启调试模式,join必须要有$my->join();var_dump($my->isTerminated(), $my->getTerminationInfo());}
<?phpnamespace app\\logic;/*** Created by PhpStorm.* User: Xgh* Date: 2020/6/3* Time: 10:50*/class ThreadBase extends \\Thread{public static $database; //静态数据库连接对象public static $noraml; //普通常量public static $arr; //普通数组public function debug($r){$str = \"[\".date(\'H:i:s\',time()).\"]:\".serialize($r).\"\\r\\n\";file_put_contents(\'\\public/1.txt\',$str,FILE_APPEND);}}
<?phpnamespace app\\logic;use app\\model\\User;use think\\Db;use think\\facade\\Debug;use app\\model\\Buy;class Distrubut extends ThreadBase{protected $user_id;public $data;public function run(){//$this->debug(var_export($this->database,true));//$this->debug(parent::$database);//$this->debug(parent::$noraml);//$this->debug(parent::$arr);//$this->debug(parent::$database);}}
遇到的问题
- 如果遇到无法启动此程序,因为计算机中丢失pthreadVC2.dll
系统64位系统应将pthreadVC2.dll复制到C:\\Windows\\SysWOW64中,而不是C:\\Windows\\System32 - thinkphp5.1 数据库和其他函数都用不了?
- 线程类的属性不能直接进行哈希表(数组)操作
因为线程类属性的赋值是通过序列化实现的,其本质是存储了序列化数据,因此不支持PHP常用直接操作哈希表(数组)的操作。 - 线程类的属性不能是“闭包函数”
原因:闭包函数不能序列化;因此,如果想在线程里用“回调函数”的话,那就放弃线程吧;
下载资源路径
官方多线程扩展下载链接-支持PHP版本5.3~7.0
PHP各个版本下载
心得
1.多线程难调试
2.使用框架难上加难
原本想用多线程去和单进程的效率和占用的对比学习的,就发现使用多线程遇到种种问题。后面就放弃了。我来列举一下遇到的几个问题,如:在使用多线程的时候,想要执行run,但是他会报错Class ‘think\\db\\Connection’ not found,因为这个对象资源都被置空了,所以会被找到NOT FOUNT,需要重新引入。所以神烦。多线程资源被置空,那我还不如使用多进程去处理,更方便调试,也更容易执行,其概念个人觉得与多进程没有多大区别了。当然网上还有一些异步执行的方式,比如swoole的异步执行,或者fsockopen。其实都是比较不错的方法的,下一篇来研究一下swoole的异步执行和携程概念。上面的资源有需要的留下邮箱!!
应用场景:个人觉得使用多线程的场景暂时不多,一般是需要程序会被阻塞并且做一些可异步执行的程序才会用到,就比如爬虫,发送信息,邮箱,或者执行一些比较耗时的,可使用这个。但是也可以用我上述的方法亦可。