首页
关于
Search
1
给你10个市场数据调研报告的免费下载网站!以后竞品数据就从这里找!
184 阅读
2
php接口优化 使用curl_multi_init批量请求
144 阅读
3
《从菜鸟到大师之路 ElasticSearch 篇》
107 阅读
4
2024年备考系统架构设计师
104 阅读
5
PHP 文件I/O
92 阅读
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
登录
Search
标签搜索
php函数
php语法
性能优化
安全
错误和异常处理
问题
vue
Composer
Session
缓存
框架
Swoole
api
并发
异步
正则表达式
php-fpm
mysql 索引
开发规范
协程
dafenqi
累计撰写
786
篇文章
累计收到
33
条评论
首页
栏目
php
thinkphp
laravel
工具
开源
mysql
数据结构
总结
思维逻辑
令人感动的创富故事
读书笔记
前端
vue
js
css
书籍
开源之旅
架构
消息队列
docker
教程
代码片段
副业
redis
服务器
nginx
linux
科普
java
c
ElasticSearch
测试
php进阶
php基础
页面
关于
搜索到
560
篇与
的结果
2023-08-09
PHP并发IO编程之路
PHP并发IO编程之路
2023年08月09日
37 阅读
0 评论
0 点赞
2023-08-09
PHP中的线程安全
PHP中的线程安全缘起TSRM在多线程系统中,进程保留着资源所有权的属性,而多个并发执行流是执行在进程中运行的线程。如Apache2 中的woker,主控制进程生成多个子进程,每个子进程中包含固定的线程数,各个线程独立地处理请求。同样,为了不在请求到来时再生成线程,MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;而MaxClients设置了所有子进程中的线程总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。当PHP运行在如上类似的多线程服务器时,此时的PHP处在多线程的生命周期中。在一定的时间内,一个进程空间中会存在多个线程,同一进程中的多个线程公用模块初始化后的全局变量,如果和PHP在CLI模式下一样运行脚本,则多个线程会试图读写一些存储在进程内存空间的公共资源(如在多个线程公用的模块初始化后的函数外会存在较多的全局变量),此时这些线程访问的内存地址空间相同,当一个线程修改时,会影响其它线程,这种共享会提高一些操作的速度,但是多个线程间就产生了较大的耦合,并且当多个线程并发时,就会产生常见的数据一致性问题或资源竞争等并发常见问题,比如多次运行结果和单线程运行的结果不一样。如果每个线程中对全局变量、静态变量只有读操作,而无写操作,则这些个全局变量就是线程安全的,只是这种情况不太现实。为解决线程的并发问题,PHP引入了TSRM: 线程安全资源管理器(Thread Safe Resource Manager)。TRSM 的实现代码在 PHP 源码的 /TSRM 目录下,调用随处可见,通常,我们称之为 TSRM 层。一般来说,TSRM 层只会在被指明需要的时候才会在编译时启用(比如,Apache2+worker MPM,一个基于线程的MPM),因为Win32下的Apache来说,是基于多线程的,所以这个层在Win32下总是被开启的。TSRM的实现进程保留着资源所有权的属性,线程做并发访问,PHP中引入的TSRM层关注的是对共享资源的访问,这里的共享资源是线程之间共享的存在于进程的内存空间的全局变量。当PHP在单进程模式下时,一个变量被声明在任何函数之外时,就成为一个全局变量。PHP解决并发的思路非常简单,既然存在资源竞争,那么直接规避掉此问题,将多个资源直接复制多份,多个线程竞争的全局变量在进程空间中各自都有一份,各做各的,完全隔离。以标准的数组扩展为例,首先会声明当前扩展的全局变量,然后在模块初始化时会调用全局变量初始化宏初始化array的,比如分配内存空间操作。这里的声明和初始化操作都是区分ZTS和非ZTS,对于非ZTS的情况,直接就是声明变量,初始化变量。对于ZTS情况,PHP内核会添加TSRM,对应到这里的代码就是声明时不再是声明全局变量,而是用ts_rsrc_id代码,初始化是不再是初始化变量,而是调用ts_allocate_id函数在多线程环境中给当前这个模块申请一个全局变量并返回资源ID。资源ID变量名由模块名和global_id组成。它是一个自增的整数,整个进程会共享这个变量,在进程SAPI初始调用,初始化TSRM环境时,id_count作为一个静态变量将被初始化为0。这是一个非常简单的实现,自增。确保了资源不会冲突,每个线程的独立。资源id的分配当通过ts_allocate_id函数分配全局资源ID时,PHP内核会锁一下,确保生成的资源ID的唯一,这里锁的作用是在时间维度将并发的内容变成串行,因为并发的根本问题就是时间的问题。当加锁以后,id_count自增,生成一个资源ID,生成资源ID后,就会给当前资源ID分配存储的位置,每一个资源都会存储在 resource_types_table 中,当一个新的资源被分配时,就会创建一个tsrm_resource_type。每次所有tsrm_resource_type以数组的方式组成tsrm_resource_table,其下标就是这个资源的ID。其实我们可以将tsrm_resource_table看做一个HASH表,key是资源ID,value是tsrm_resource_type结构。只是,任何一个数组都可以看作一个HASH表,如果数组的key值有意义的话。 resource_types_table的定义如下:typedef struct { size_t size;//资源的大小 ts_allocate_ctor ctor;//构造方法指针 ts_allocate_dtor dtor;//析构方法指针 int done; } tsrm_resource_type;在分配了资源ID后,PHP内核会接着遍历所有线程为每一个线程的tsrm_tls_entry分配这个线程全局变量需要的内存空间。这里每个线程全局变量的大小在各自的调用处指定。每一次的ts_allocate_id调用,PHP内核都会遍历所有线程并为每一个线程分配相应资源,如果这个操作是在PHP生命周期的请求处理阶段进行,岂不是会重复调用?PHP考虑了这种情况,ts_allocate_id的调用在模块初始化时就调用了。在模块初始化阶段,通过SAPI调用tsrm_startup启动TSRM,tsrm_startup函数会传入两个非常重要的参数,一个是expected_threads,表示预期的线程数,一个是expected_resources,表示预期的资源数。不同的SAPI有不同的初始化值,比如mod_php5,cgi这些都是一个线程一个资源。TSRM启动后,在模块初始化过程中会遍历每个扩展的模块初始化方法,扩展的全局变量在扩展的实现代码开头声明,在MINIT方法中初始化。其在初始化时会知会TSRM申请的全局变量以及大小,这里所谓的知会操作其实就是前面所说的ts_allocate_id函数。TSRM在内存池中分配并注册,然后将资源ID返回给扩展。后续每个线程通过资源ID定位全局变量,比如我们前面提到的数组扩展,如果要调用当前扩展的全局变量,则使用:ARRAYG(v),这个宏的定义:ifdef ZTS #define ARRAYG(v) TSRMG(array_globals_id, zend_array_globals *, v) #else #define ARRAYG(v) (array_globals.v) #endif如果是非ZTS则直接调用全局变量的属性字段,如果是ZTS,则需要通过TSRMG获取变量。TSRMG的定义:define TSRMG(id, type, element) (((type) (((void **) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(id)])->element)去掉这一堆括号,TSRMG宏的意思就是从tsrm_ls中按资源ID获取全局变量,并返回对应变量的属性字段。那么现在的问题是这个tsrm_ls从哪里来的?其实这在我们写扩展的时候会经常用到:define TSRMLS_D void *tsrm_ls #define TSRMLS_DC , TSRMLS_D #define TSRMLS_C tsrm_ls #define TSRMLS_CC , TSRMLS_C以上为ZTS模式下的定义,非ZTS模式下其定义全部为空。最后个问题,tsrm_ls是从什么时候开始出现的,从哪里来?要到哪里去?答案就在php_module_startup函数中,在PHP内核的模块初始化时,如果是ZTS模式,则会定义一个局部变量tsrm_ls,这就是我们线程安全开始的地方。从这里开始,在每个需要的地方通过在函数参数中以宏的形式带上这个参数,实现线程的安全。
2023年08月09日
10 阅读
0 评论
0 点赞
2023-08-09
PHP设计模式
PHP设计模式阅读文档
2023年08月09日
18 阅读
0 评论
0 点赞
2023-08-09
composer收藏集
composer之创建自己的包PHP项目中composer和Git的组合使用基于composer的php项目的性能优化
2023年08月09日
9 阅读
0 评论
0 点赞
2023-08-09
结合Composer 新版本PHP的开发方式
结合Composer 新版本PHP的开发方式一、PHP的一些臭历史Dependency Manager For PHP,Composer。在Composer还没诞生之前,PHP的代码很难被管理。虽然pear社区的支持,许多可重用代码可以通过pear来获得,但是pear在处理代码关联性上非常差,当然还有许多问题。Java领域有Maven工具, .Net 的VS工具集成了NuGet,都是非常好使的关联管理器。但是PHP何去何从?Composer诞生了。它的诞生很大意义上是因为php的3.0版本被普及了,php的命名空间特性让代码包可以在全球级别上具备唯一识别性。当然有人说,我们可以在一个类的命名上做文章也可以做到,但是,会带来许多问题,类名太长,命名重名性高,文件的组织性识别性差等等。PHP根本无法忽略java,.net一直在被使用的package与命名空间的特性,php必须换血。随着php3.0的普及,通过众多第三方的努力,PHP社区迅猛的积累了许多可用的代码库,起初,大部分代码库都是分享在Github,采用git的方式获取。虽然这个可取,但是关联管理以及操作性上还是比较差。我们需要一个更加简单的具备关联管理的代码库管理工具。Yeah。Composer。好了,说到这里,或许许多人还很模糊。没关系,我们采用尝试动手,来熟悉Composer。二、初体验ComposerComposer具体点是什么? 就是一个编译压缩过的phar文件,一个可以执行的工具。怎么获取?Linux下$ curl -sS https://getcomposer.org/installer | phpwindows下C:\Users\username>cd C:\binC:\bin>php -r "readfile('https://getcomposer.org/installer');" | php完了,你可以在控制台下,输入命令 php composer.phar 来获取composer的使用帮助。下面我们来演示一下,如何使用Composer来创建一个PHP项目首先,创建一个项目目录ComposerDemo进入目录之后,使用以上命令来获取composer.phar,当然composer是可以全局配置,意思为不需要一个php项目下载一个Composer,而是共用一个Composer接下来 调用 php composer.phar init 可以自动创建一个 composer.json文件,当然你也可以手工创建。{"name": "kendoctor/composer_demo", "description": "introduction for how to use composer", "minimum-stability": "stable", "authors": [ { "name": "kendoctor", "email": "kendoctor@163.com" } ], "require": { }}这个文件很重要,它告诉composer如何工作。初始创建的模版,你可以修正一些你的项目的信息。name ,项目名称,命名规则,vendor名称/项目名称description,项目描述minium-stability,版本类型,具体内容参考官方阐述。这里先不作探讨。authors,作者信息。require, 这里可以请求你项目其他的相关php类库或类库包下面我们来演示Composer的第一个特性,类的自动载入首先,按照目录结构来创建文件ComposerDemo/├── composer.phar├── composer.json├── src/│ ├── models│ ├── Calculator.php├── index.php文件Calculator.php<?php/**Created by JetBrains PhpStorm.User: KendoctorDate: 14-3-19Time: 上午9:39To change this template use File | Settings | File Templates. */class Calculator {public function addNumbers($x,$y) { return $x + $y; }}我们要使用类Calculator,php老办法就是require这个类文件。事实上,我们在代码中会调用许多类,而这些类都会放到不同的文件中,那样的话,我们需要许多的require。我们知道index.php可以这么写<?php/**Created by JetBrains PhpStorm.User: kendoctorDate: 14-3-19Time: 上午9:40To change this template use File | Settings | File Templates. */require("src/models/Calculator.php");$calc = new Calculator();echo $calc->addNumbers(10,21);但是,这不是我们用了Composer想要的。我们要的效果是,实例某个类,它会自动载入。那,怎么搞呢?修改Composer.json{"name": "kendoctor/composer_demo", "description": "description_text", "minimum-stability": "stable", "authors": [ { "name": "author's name", "email": "email@example.com" } ], "autoload":{ "classmap": ["src/"] } }require这个属性被我删除了,稍等我们再来介绍其特性。首先这里引入一个autoload属性,可以自动加载类或命名空间的特性属性。classmap属性定义要引入的哪个目录下的类,或者直接可以是类文件。我们这里指定src目录下所有的类文件。修改之后,我们要通过composer命令来更新一下目录结构内容,很简单php composer.php dump-autoload完了会自动产生目录vendor,里面许多自动产生的内容,不过这里,我们只需要关注autoload.php这个文件。我们在index.php只需要引入这个文件就可以了<?php/**Created by JetBrains PhpStorm.User: kendoctorDate: 14-3-19Time: 上午9:40To change this template use File | Settings | File Templates. */require("vendor/autoload.php");$calc = new Calculator();echo $calc->addNumbers(10,21);如果你又新添加了一个User到models目录下,那你无需要做其他工作,就可以直接在index.php文件中直接调用此类了。
2023年08月09日
9 阅读
0 评论
0 点赞
1
...
66
67
68
...
112