PHP Swoole进程间使用共享内存通信

2021-10-03

Swoole/table优势

  1. 性能强悍,单线程每秒可读写 200 万次;
  2. 代码无需加锁,Table 内置行锁自旋锁,所有操作均是多线程/多进程安全。用户层完全不需要考虑数据同步问题;
  3. 支持多进程,Table 可以用于多进程之间共享数据;
  4. 使用行锁,而不是全局锁,仅当2个进程在同一 CPU时间,并发读取同一条数据才会进行发生抢锁。
use Swoole\Process;
use Swoole\Coroutine;
use Swoole\Table;

// 共享内容一经设置无法扩容,底层建立在共享内存上
// $size应是2的N次方,最小值64,table的最大行数略小于$size
$table = new Table($size = 1024);
// 给表格增加一列$file_name,类型为$type,最大长度为$size;
$table->column($file_name1 = 'int1', $file_type1 = Table::TYPE_INT); // 默认占8个字节
$table->column($file_name2 = 'float1', $file_type2 = Table::TYPE_FLOAT); // 占用8个字节
$table->column($file_name3 = 'string1', $file_type3 = Table::TYPE_STRING, $size = 1024); // 不能超过$size指定的最大长度,超出时底层自动截断

// 创建内存表,创建后不能再添加列
if (!$table->create()) {
	echo '系统内存不足';
}

var_dump('表格最大行数:' . $table->size);
var_dump('表格占用内容(字节):' . $table->memorySize);


$worker1 = new Process(function ($process) use ($table) {
	// 在表格中添加一行;相同的$key为同一行,多次添加会覆盖;$key不能超过63字节;数组数组必须与添加的列名称相同
	if (!$table->set($key = '1', array('int1' => 1, 'float1' => 1.12, 'string1' => '测试1'))) {
		echo '添加失败,内存不足';
	}
	if (!$table->set($key = '2', array('int1' => 2, 'string1' => '测试2'))) {
		echo '添加失败,内存不足';
	}

	$table->set($key = '3', array('int1' => 3, 'float1' => 1.32));
	// 对$key的指定列$field_name自增$incrby,自增自减只能对整型和浮点型列处理,且自增自减的值要对应列的类型
	$table->incr($key = '3', $field_name = 'int1', $incrby = 1);
	// 对$key的指定列$field_name自减$incrby
	$table->decr($key = '3', $field_name = 'float1', $incrby = 1.0);
});
$worker1->start();

$worker2 = new Process(function ($process) use ($table) {
	while (1) {
		var_dump('表格中的行数:' . $table->count());

		foreach ($table as $key1 => $value) {
			// 检查table是否存在指定$key
			if ($table->exist($key = '1')) {
				// 删除指定$key的数据
				$table->del($key = '1');
			}	
			// 获取表格中指定的$key的一行或一个字段的数据
			$table->get($key1, $field_name = null);
			var_dump($value);
		}
		Coroutine::sleep(1);
	}
}, false, 1, true);
$worker2->start();

while ($status = Process::wait(true)) {
	echo "Recycled #{$status['pid']}, code={$status['code']}, signal={$status['signal']}" . PHP_EOL;
}

 

{/if}