首页
导航
博客
电子书
算法
众创
代码
随贴
关于我们
您好,欢迎来到码863代码分享网! 请
[登录]
/
[注册]
搜 索
标题:
*
140
字
TAG标签:
(用空格隔开)
30
字
恢复历史版本:
请选择分类
html
python
javascript
php
sql
c
c++
c#
java
plain
所有人可见
仅自己可见
编辑器:UEditor
编辑器:TinyMCE
编辑器:Editor.md
HTML转MD
HTML转MD2
<p>由于原生PHP不支持多线程模型,所以Swoole更多时候使用多进程模型,因此代码相对更加简洁,减少了各种线程锁的阻塞和同步,但同时也带来了新的问题:数据共享。由于多线程可以直接共享进程的内存,进程之间数据的相互同步则需要依赖于共享内存。</p><p>原生PHP进程之间是不能相互通信的,在<code>swoole_process</code>中则是可以的,Swoole中进程之间的通信是通过管道<code>pipe</code>来传递的。多进程、多线程之间的数据共享则是通过内存<code>memory</code>来实现的。</p><p><code>swoole_table</code>共享内存表是一个基于共享内存和锁实现的超高性能并发数据结构,用于解决多进程或多线程数据共享和同步加锁问题,它不消耗服务器 IO,纯内存操作,性能十分强悍。</p><p>优势</p><p>共享内存表可以直接操作系统的内存,性能强悍,单线程每秒可读写200万每次,主要用于进程间的数据通信。</p><p>共享内存表应用代码无需加锁,内置行锁自旋锁,所有操作都是多进程或多线程安全,用户层完全不需要考虑数据同步问题。</p><p>共享内存表支持多进程,内存表可以用于多进程之间共享数据。</p><p>共享内存表使用行锁而非全局锁,仅当两个进程在同一CPU时间并发读取同一条数据时才会发生抢锁。</p><p>共享内存表不受PHP的<code>memory_limit</code>最大内存的控制</p><p>适用场景:用于解决多进程或多线程数据共享和同步加锁问题,进程结束后共享内存表会自动释放。</p><pre class="line-numbers language-php"><?phpuse Swoole\Table;//创建共享内存表对象$size = 1024;//2的n次方$table = new swoole_table($size);//共享内存表添加字段$table->column("id", Table::TYPE_INT, 11);$table->column("name", Table::TYPE_STRING, 20);$table->column("money", Table::TYPE_FLOAT, 10);$table->create();//共享内存表添加行$table->set("alice", ["id"=>1, "name"=>"alice", "money"=>100.5]);//使用数组方式添加行$table["ben"] =["id"=>2, "name"=>"ben", "money"=>200.1];//获取行返回数组$val = $table->get("alice");var_dump($val);//获取行返回对象$val = $table["ben"];var_dump($val);//共享内存表内字段值增加$table->incr("alice", "money", 100);var_dump($table["alice"]);//共享内存表中字段值减少$table->decr("ben", "money", 50);var_dump($table["ben"]);echo json_encode($table).PHP_EOL;</pre><h2>创建对象<code>construct</code></h2><p>创建共享内存表,实测$size*2才不报分配内存不足</p><pre class="line-numbers language-php">function Table->__construct(int $size, float $conflict_propertion = 0.2);</pre><p>共享内存表实际上是一个开链法实现的哈希表,内存是由哈希键<code>Key</code>与具体数据组成的数组,如果哈希冲突即不同的键值对一个同一个哈希,那么就会从内存池<code>pool</code>中分配出一个元素作为数组元素的链表尾。</p><p>内存表占用的内存总数 = ( 结构体长度 + 哈希键长度<code>64byte</code> + 行尺寸<code>$size</code> ) * 预留作为哈希冲突的百分比 * 列尺寸</p><p>参数1:<code>int $size</code></p><p><code>$size</code>表示创建共享内存表时设置的最大行数,必须是2的次方,如果不是底层会自动调整为接近的一个数字,若小于1024则默认为1024,即1024为最小值。若机器内存不足内存表会创建失败。</p><p>共享内存表底层是建立在共享内存之上的哈希表<code>HashTable</code>(数据结构),最大行数<code>$size</code>决定了哈希表的总行数。由于内存表是在共享内存之上,所以无法动态扩容,因此<code>$size</code>必须在创建前提前设置好。</p><p>参数2:<code>float $conflict_propertion</code> 哈希冲突率</p><p>如果哈希冲突超过最大比例,共享内存表将不再允许添加新的行元素。共享内存表能存储的总数据行数取决于数据的哈希键冲突率,默认如果冲突率超过20%,预留的哈希<code>hash</code>冲突内存块容量不足,会报<code>Unable to allocate memory</code>无法分配内存的错误,并返回<code>false</code>表示存储失败。</p><pre class="line-numbers language-php"><?phpuse Swoole\Table;//创建共享内存表对象$size = 1024;//2的n次方$table = new swoole_table($size);$table->column("data", Table::TYPE_STRING, 1);$table->create();echo json_encode($table).PHP_EOL;// {"size":1024,"memorySize":117548}</pre><h2>添加列数据<code>column</code></h2><p>共享内存表新增一列</p><pre class="line-numbers language-php">bool Table->column(string $name, int $type, int $size = 0)swoole_table->column(string $name, int $type, int $size = 0)</pre><p>参数列表</p><ul class=" list-paddingleft-2"><li><p><code>string $name</code> 表示字段的名称</p></li><li><p><code>int $type</code> 表示字段类型,可支持3种类型分别是<code>Table::TYPE_INT</code>、<code>Table::TYPE_FLOAT</code>、<code>Table::TYPE_STRING</code>。</p></li><li><p><code>int $size</code> 表示字符串字段的最大长度单位字节,字符串类型<code>Table::TYPE_STRING</code>的字段必须指定<code>$size</code>。</p></li></ul><p>字段类型</p><ul class=" list-paddingleft-2"><li><p><code>Table::TYPE_INT</code> 整型默认4字节,可设置1、2、4、8共四种长度。</p></li><li><p><code>Table::TYPE_STRING</code> 字符型必须指定,设置的字符串不得超过设置值。</p></li><li><p><code>Table::TYPE_FLOAT</code> 浮点型,占用8字节的内存。</p></li></ul><p>整型溢出</p><p>由于Swoole底层使用有符号整型,如果传入的数值超过溢出边界就可能会发生溢出。</p><p>整数类型安全值的范围</p><ul class=" list-paddingleft-2"><li><p><code>int8</code> 1byte -127 ~127</p></li><li><p><code>int16</code> 2byte -32767~327767</p></li><li><p><code>int32</code> 4byte -2147483647 ~ 2147483647</p></li><li><p><code>int64</code> 8byte 不会溢出</p></li></ul><p>内存对齐</p><p>从Swoole4.3版本开始,底层对内存长度做了对齐处理。字符串长度必须是8的整数倍,如果长度为18字节会自动对其到24字节。注意非<code>x86</code>环境则内存对齐。</p><h2>创建共享内存表<code>create</code></h2><p>当定义好表的结构后执行<code>create</code>会向操作系统申请内存并创建共享内存表。需要注意的是,调用<code>create</code>创建之前不能使用<code>set</code>、<code>get</code>等数据读写操作,调用<code>create</code>创建之后不能使用<code>column</code>添加新字段。如果 系统内存不足则会申请失败此时<code>create</code>将返回<code>false</code>,若申请成功<code>create</code>将会返回<code>true</code>。</p><p><code>Table</code>使用共享内存来保存数据,在创建子进程之前,务必要执行<code>create</code>执行创建。服务器中使用共享内存表执行<code>create</code>创建操作必须在服务器执行<code>start</code>启动方法之前。</p><p>当使用<code>create</code>方法创建共享内存表后,可以读取<code>$table->memorySize</code>属性来获取实际占用的内存尺寸,单位为字节。</p><pre class="line-numbers language-jsx">function Table->create():bool</pre><h2>设置行数据<code>set</code></h2><p>共享内存表使用键值对的方式存取数据</p><pre class="line-numbers language-php">Table->set(string $key, array $value):bool</pre><p>参数列表</p><p>参数1:<code>string $key</code></p><p>设置行数据对应的键名,相同的键名对应同一行数据,如果<code>set</code>设置了同一个键名则会覆盖上一次的数据。</p><p>参数2:<code>array $value</code></p><p>设置行数据对应的键值,必须是一个数组,必须与字段定义的名称<code>$name</code>完全相同。</p><p>返回值</p><p>设置成功返回<code>true</code>,设置失败返回<code>false</code>,失败的原因可能是由于哈希冲突过多导致动态空间无法分配内存,可以调大构造方法的<code>$conflict_propertion</code>参数。</p><p>如果传入字符串的长度超过列定义的最大尺寸,底层会自动截断。</p><h2>获取行数据<code>get</code></h2><p>获取单行数据</p><pre class="line-numbers language-php">array Table->get(string $key, string $field = null)</pre><p>参数列表中<code>string $key</code>表示查询数据行的键名,必须为字符串类型。</p><p>如果带查询的键名不存在,则<code>get</code>方法将会返回<code>false</code>。若成功则返回的结果为数组类型。</p><h2>检查键名是否存在<code>exist</code></h2><p><code>exist</code>方法用于检查共享内存表中是否存在某个键名<code>key</code>,若存在则返回<code>true</code>,否则返回<code>false</code>。</p><pre class="line-numbers language-php">bool swoole_table->exists(string $key)</pre><h2>条目数量<code>count</code></h2><p><code>count</code>方法用于获取共享内存表<code>table</code>中存在的条目数量</p><pre class="line-numbers language-php">int function Table->count()</pre><h2>删除键值对<code>del</code></h2><pre class="line-numbers language-php">bool Table->del(string $keyy)</pre><p><code>del</code>方法用于删除共享内存表<code>$table</code>中指定键名<code>$key</code>的行,如果键名<code>$key</code>对应的是数据不存在则返回<code>false</code>,否则成功返回<code>true</code>。此处需要注意的是键名<code>$key</code>是非二进制安全的,所以必须为字符串类型,因此不得传入二进制数据。</p><h3>原子递增<code>incr</code></h3><pre class="line-numbers language-php">function Table->incr(string $key, string $column. mixed $incrby = 1): int</pre><ul class=" list-paddingleft-2"><li><p><code>incr</code>表示原子递增操作,参数<code>string $key</code>表示指定数据的键名,如果键名对应的行不存在则默认值为0。</p></li><li><p><code>int column</code> 表示指定的列表即字段名,仅支持浮点型和整型字段。</p></li><li><p><code>int $incrby</code>表示则增量默认为1,若列为整型则增量必须为整型,如果列为浮点型则增量必须为浮点型。</p></li></ul><p>返回最终的结果数值</p><h2>原子自减<code>decr</code></h2><pre class="line-numbers language-php">function Table->decr(string $key, string $column, mixed $decrby = 1) int | bool</pre><p>参数列表</p><ul class=" list-paddingleft-2"><li><p><code>string $key</code>表示指定数据的键名,如果键名对应的行不存在,底层会首先将该行数据初始化为0。</p></li><li><p><code>string $column</code>表示指定的列名,仅支持浮点型和整型字段。</p></li><li><p><code>mixed $decrby</code>表示减量默认为1,如果列为整型则减量必须也为整型,同样如果列为浮点型则减量也必须为浮点型。</p></li></ul><p>返回值将返回最终的结果数值,数值为0时递减会变成负数。</p><p>实例:创建swoole_table用于进程间数据共享</p><pre class="line-numbers language-php"><?phpclass Server{ private $server; public function __construct($host="0.0.0.0", $port = 9501, $size = 1024) { //创建swoole_table用于进程间数据共享 $table = new swoole_table($size); $table->column("fd", swoole_table::TYPE_INT); $table->column("uid", swoole_table::TYPE_INT); $table->column("type", swoole_table::TYPE_STRING, 256); $table->column("data", swoole_table::TYPE_STRING, 256); $table->create(); //创建WebServer服务器对象 $this->server = new swoole_websocket_server($host, $port); $this->server->table = $table; //注册事件回调函数 $this->server->on("handShake", [$this, "onHandShake"]); $this->server->on("workerStart", [$this, "onWorkerStart"]); $this->server->on("open", [$this, "onOpen"]); $this->server->on("message", [$this, "onMessage"]); $this->server->on("close", [$this, "onClose"]); //开启服务器 $this->server->start(); } public function onHandShake($server) { echo "[handshake]".PHP_EOL; } public function onWorkerStart($server) { echo "[workerstart]".PHP_EOL; } public function onOpen($server) { echo "[open]".PHP_EOL; } public function onMessage($server) { echo "[message]".PHP_EOL; } public function onClose($message) { echo "[close]".PHP_EOL; }}$server = new Server();</pre><p><br/><br/>作者:JunChow520<br/>链接:https://www.jianshu.com/p/1dae870407bc<br/>来源:简书<br/>著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。</p><p><br/></p>
CopyRight 2002~2023 精通2100网 联系邮箱:qqtxt@163.com
版权所有:精通2100网
湘ICP备2023018646号-1
MYSQl共执行 4 个查询,用时 0.0022950172424316 秒,PHP脚本用时 0.004912 秒,占用内存 0.597 MB,Gzip 已启用