Swoole入门到实战(二):进程,内存和协程、Swoole完美支持ThinkPHP5
转载自:https://cloud.tencent.com/developer/article/1435843?from_column=20421&from=20421
一、进程,内存和协程
1.1 进程
1.1.1 进程
进程就是
正在运行的程序
的一个实例
$process = new swoole_process(function(swoole_process $pro) {
// todo
// php redis.php
$pro->exec("/usr/local/php/bin/php", [__DIR__.'/../server/http_server.php']);
}, false);
$pid = $process->start();
echo $pid . PHP_EOL;
//回收结束运行的子进程
swoole_process::wait();
以**树状图**显示进程间的关系:`pstree -p 进程id`
启动成功后会创建`worker_num+2`个进程。`Master`进程+`Manager`进程+`serv`->`worker_num`个`Worker`进程
1.1.2 进程使用场景
管道:进程和进程间的一个桥梁
echo "process-start-time:".date("Ymd H:i:s");
$workers = [];
$urls = [
'http://baidu.com',
'http://sina.com.cn',
'http://qq.com',
'http://baidu.com?search=singwa',
'http://baidu.com?search=singwa2',
'http://baidu.com?search=imooc',
];
//创建多个子进程分别模拟请求URL的内容
for($i = 0; $i < 6; $i++) {
$process = new swoole_process(function(swoole_process $worker) use($i, $urls) {
// curl
$content = curlData($urls[$i]);
//将内容写入管道
// echo $content.PHP_EOL;
$worker->write($content.PHP_EOL);
}, true);
$pid = $process->start();
$workers[$pid] = $process;
}
//获取管道内容
foreach($workers as $process) {
echo $process->read();
}
/**
* 模拟请求URL的内容 1s
* @param $url
* @return string
*/
function curlData($url) {
// curl file_get_contents
sleep(1);
return $url . "success".PHP_EOL;
}
echo "process-end-time:".date("Ymd H:i:s");
1.2 Swoole内存-table详解
内存操作模块之:
Table
swoole_table
一个基于共享内存和锁实现的超高性能,并发数据结构
使用场景:用于解决多进程/多线程
数据共享和同步加锁问题
进程结束后内存表会自动释放
// 创建内存表
$table = new swoole_table(1024);
// 内存表增加一列
$table->column('id', $table::TYPE_INT, 4);
$table->column('name', $table::TYPE_STRING, 64);
$table->column('age', $table::TYPE_INT, 3);
$table->create();
$table->set('singwa_imooc', ['id' => 1, 'name'=> 'singwa', 'age' => 30]);
// 另外一种方案
$table['singwa_imooc_2'] = [
'id' => 2,
'name' => 'singwa2',
'age' => 31,
];
$table->decr('singwa_imooc_2', 'age', 2);
print_r($table['singwa_imooc_2']);
echo "delete start:".PHP_EOL;
$table->del('singwa_imooc_2');
print_r($table['singwa_imooc_2']);
1.3 协程
$http = new swoole_http_server('0.0.0.0', 9001);
$http->on('request', function($request, $response) {
// 获取redis 里面 的key的内容, 然后输出浏览器
$redis = new Swoole\Coroutine\Redis();
$redis->connect('127.0.0.1', 6379);
$value = $redis->get($request->get['a']);
// mysql.....
//执行时间取它们中最大的:time = max(redis,mysql)
$response->header("Content-Type", "text/plain");
$response->end($value);
});
$http->start();
二、Swoole完美支持ThinkPHP5(重难点
)
2.1 面向过程方案
2.1.1 面向过程代码实现
$http = new swoole_http_server("0.0.0.0", 9911);
$http->set(
[
'enable_static_handler' => true,
'document_root' => "/home/wwwroot/swoole/thinkphp/public/static",
'worker_num' => 5,
]
);
//此事件在Worker进程/Task进程启动时发生,这里创建的对象可以在进程生命周期内使用
$http->on('WorkerStart', function(swoole_server $server, $worker_id) {
// 定义应用目录
define('APP_PATH', __DIR__ . '/../../../../application/');
// 加载框架里面的文件
require __DIR__ . '/../../../../thinkphp/base.php';
});
$http->on('request', function($request, $response) use($http){
//如果在每次请求时加载框架文件,则不用修改thinkphp5源码
// // 定义应用目录
// define('APP_PATH', __DIR__ . '/../../../../application/');
// // 加载框架里面的文件
// require_once __DIR__ . '/../../../../thinkphp/base.php';
/**
* 解决上一次输入的变量还存在的问题
* 方案一:if(!empty($_GET)) {unset($_GET);}
* 方案二:$http-close();把之前的进程kill,swoole会重新启一个进程,重启会释放内存,把上一次的资源包括变量等全部清空
* 方案三:$_SERVER = []
*/
$_SERVER = [];
if(isset($request->server)) {
foreach($request->server as $k => $v) {
$_SERVER[strtoupper($k)] = $v;
}
}
if(isset($request->header)) {
foreach($request->header as $k => $v) {
$_SERVER[strtoupper($k)] = $v;
}
}
$_GET = [];
if(isset($request->get)) {
foreach($request->get as $k => $v) {
$_GET[$k] = $v;
}
}
$_POST = [];
if(isset($request->post)) {
foreach($request->post as $k => $v) {
$_POST[$k] = $v;
}
}
//开启缓冲区
ob_start();
// 执行应用并响应
try {
think\Container::get('app', [APP_PATH])
->run()
->send();
}catch (\Exception $e) {
// todo
}
//输出TP当前请求的控制方法
//echo "-action-".request()->action().PHP_EOL;
//获取缓冲区内容
$res = ob_get_contents()