php多进程共享数据库,PHP多进程环境下通过共享内存与信号量实现资源共享

PHP多进程环境下通过共享内存与信号量实现资源共享

目前工作环境,由于一些原因,不能使用swoole,和其他多进程的管理组件。但是项目中有大量的功能必须通过多进程来实现。面对这也不能,那也不能的困境,总要想一些办法来多快好省的完成工作。

项目中其他成员,使用多进程的方式,通过shell 起多个脚本,完成多进程的开发,效果也不错。我这边主要使用pcntl_fork 这个PHP自带的扩展来起进程。

在项目的开发过程中,比如我需要通过10个进程消费100万的数据,在进程环境内,无法将多个进程已经消费的数据汇总起来。

需求点:

多进程环境下,进程之间通信困难,编写通信代码也比较繁琐。

进程间通信,比如获取值,对值进行操作,面临锁的问题。

下面是通过共享内存,与信号量实现的进程间通信

class Test

{

private $processArr = [];

private $shmId = null;

private $semId = null;

private $ftokId = null;

const SHARE_MEMORY_SIZE = 4096; //申请4k 作为共享内存

//共享内存配置类似

private $shareKeyConfig = array(

"count" => array(

"start" => 0,

"end" => 127,

),

"consume" => array(

"start" => 128,

"end" => 255,

),

);

/**

* 初始化参数

* Test constructor.

* @param array $shareKeyConfig

*/

public function __construct($shareKeyConfig = [])

{

if ($shareKeyConfig) {

$this->shareKeyConfig = $shareKeyConfig;

}

return true;

}

public function renderProgress($current)

{

printf("progress: [%-50s] %d%% Done\r", str_repeat(‘#‘, $current / 600 * 50), $current / 600 * 100);

}

/**

* 启动一个进程

*/

public function run()

{

$this->initShareMemoryLock();

for ($i = 0; $i <= 5; $i++) {

$pid = pcntl_fork();

if ($pid == -1) {

die("创建子进程失败");

} elseif ($pid > 0) {

//echo "子进程{$pid}已经正常启动" . PHP_EOL;

$this->processArr[$pid] = $pid;

} else {

$this->dosomeThing();

exit();

}

}

//echo "done" . PHP_EOL;

$this->waitProcess();

//echo "done2" . PHP_EOL;

$this->removeShareMemoryLock();

}

public function dosomeThing()

{

for ($i = 1; $i <= 100; $i++) {

usleep(100000);

$this->incr("consume");

$num = (int)$this->getValue(‘consume‘);

$this->renderProgress($num);

//echo "当前内存中的数字是:{$num}" . PHP_EOL;

}

//sleep(1);

//echo "加完毕" . PHP_EOL;

return true;

}

public function waitProcess()

{

while (count($this->processArr)) {

$childPid = pcntl_wait($status);

//var_dump($childPid);

if ($childPid > 0) {

//echo "子进程{$childPid}已经正常结束" . PHP_EOL;

unset($this->processArr[$childPid]);

}

}

return true;

}

/**

* 初始化基于共享内存的锁

*/

public function initShareMemoryLock()

{

$this->checkFunctionExists();

$this->createShareMemoryCache(1);

$this->createSemaphore(1);

return true;

}

/**

* 计数器

* @param $key

* @param int $incr

*/

public function incr($key, $incr = 1)

{

sem_acquire($this->semId);

$num = (int)$this->getValue($key);

$this->setValue($key, $num + $incr);

sem_release($this->semId);

return true;

}

/**

* 根据key,获取对应的value

* @param string $key

*/

private function getValue(string $key)

{

if (!isset($this->shareKeyConfig[$key])) {

die(‘请先配置共享内存的key!‘ . PHP_EOL);

}

$config = $this->shareKeyConfig[$key];

$val = shmop_read($this->shmId, $config[‘start‘], ($config[‘end‘] - $config[‘start‘]));

return trim($val);

}

/**

* 设置共享内存

* @param string $key

* @param string $val

*/

private function setValue(string $key, string $val)

{

if (!isset($this->shareKeyConfig[$key])) {

die(‘请先配置共享内存的key!‘ . PHP_EOL);

}

$config = $this->shareKeyConfig[$key];

shmop_write($this->shmId, $val, $config[‘start‘]);

return true;

}

/**

* 创建共享内存

* 单个文件多个方法调用,必须使用不同的projectId

* @param $projectId

* @param int $size

* @return bool

*/

public function createShareMemoryCache($projectId, $size = 2048)

{

set_time_limit(0);

if ($projectId < 1 || $projectId > 255) {

die("projectId 的取值范围在1-255。" . PHP_EOL);

}

$this->ftokId = ftok(__FILE__, $projectId);

$shmId = @shmop_open($this->ftokId, "c", 0644, $size);

if (!is_resource($shmId)) {

die("shmop_open(): unable to attach or create shared memory segment ‘Permission denied‘" . PHP_EOL);

}

$this->shmId = $shmId;

return true;

}

/**

* 关闭共享内存快

*/

public function closeShareMemory()

{

shmop_delete($this->shmId);

shmop_close($this->shmId);

return true;

}

/**

* 关闭信号量

*/

public function closeSemaphore()

{

sem_remove($this->semId);

return true;

}

/**

* 关闭共享内存

* @return bool

*/

public function removeShareMemoryLock()

{

$this->closeSemaphore();

$this->closeShareMemory();

return true;

}

/**

* 创建信号量

* @param $projectId

*/

public function createSemaphore($projectId)

{

$this->semId = sem_get($this->ftokId);

return true;

}

/**

* 检测系统是否开启共享内存与信号量函数

* @return bool

*/

public function checkFunctionExists()

{

$requireFunc = array(

"ftok",

"shmop_open",

"shmop_write",

"shmop_read",

"shmop_delete",

"shmop_close",

"shmop_size",

"sem_get",

"sem_acquire",

"sem_release",

"sem_remove"

);

foreach ($requireFunc as $func) {

if (!function_exists($func)) {

die("$func 删除不存在");

}

}

return true;

}

}

$demo = new Test();

$demo->run();

原文:https://www.cnblogs.com/roverliang/p/12674505.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值