使用pthreads扩展碰到的问题
今天用pthreads来解决耗时操作阻塞主线程的问题,但是自动加载一直不成功。试了各种解决办法都不可行,直到发现别人提交的BUG,才发现无解,生产环境慎用。
具体业务在这里简化为三个文件,分别为run.php、Demo.php、Task.php,其中,run.php为入口、Task.php为线程类、Demo.php为模拟的具体逻辑。
文件内容
Demo.php
<?php namespace core; class Demo { public static function method(): string { return "Demo::method()\r\n"; } }
Task.php
<?php namespace core; class Task extends \Thread { public function run(): void { file_put_contents('temp.txt', Demo::method(), FILE_APPEND); } }
run.php
<?php // composer自动加载 require 'vendor/autoload.php'; $task = new \core\Task(); $task->start(); echo "主线程结束\r\n";
执行/复现
此处得到结果
PHP Fatal error: Uncaught Error: Class 'core\Demo' not found in C:\Users\topnuo mi\Desktop\thread\core\Task.php:9 Stack trace: #0 [internal function]: core\Task->run() #1 {main} thrown in C:\Users\topnuomi\Desktop\thread\core\Task.php on line 9 主线程结束
这个结果并不是设想到的结果,自动加载没有在子线程生效。接着再次尝试将spl_autoload_register函数写进Task的run方法中,同样不会生效,令人困惑。
总结
经过测试,主线程中的常量、函数是可以被子线程继承的,但是自动加载没有被继承,具体能继承主线程的什么只能自己去测试了,谷歌、百度都没搜到(方式不对?)。折腾一番后依然没有能解决问题,当看到有其他人已经将这个问题提交到PHP Bugs去的时候,我就基本确定这个问题暂时无解。自动加载目前来看是真的不会继承,只能靠require/include解决子线程中的文件加载问题,在依赖过多的情况下,真的会让人很难受。
已经提交的BUG如下(https://bugs.php.net/bug.php?id=72528)
另一个问题
在执行上面操作的时候,还遇到一个奇怪的问题
将Task.php改造为如下:
<?php
namespace core;
class Task extends \Thread
{
public function run(): void
{
sleep(2);
}
}
run.php入口改造为如下,开启两个子线程:
<?php
require 'vendor/autoload.php';
// 线程1
$task1 = new \core\Task();
$task1->start();
// 线程2
$task2 = new \core\Task();
$task2->start();
echo "主线程结束\r\n";
执行script.php,主线程立即执行完成,子线程在2秒后全部执行完成,是我们预想的结果。接下来换一种写法,如下:
<?php
require 'vendor/autoload.php';
// 线程1
(new \core\Task())->start();
// 线程2
(new \core\Task())->start();
echo "主线程结束\r\n";
直接new出来一个Task对象,然后调用其start方法开启线程,本来想的是2秒后执行完成,但是结果却是4秒后全部执行完成,再次令人困惑。
注:本文中的多线程实现为pthreads扩展