php序号递增代码,PHP下通过系统信号量加锁方式获取递增序列ID

PHP下通过系统信号量加锁方式获取递增序列ID

更新时间:2009年09月25日 14:43:24   作者:

前一阵子,设计LAJP时需要在PHP中生成唯一ID,看似小菜一碟却着实让我为难了,在Java中一个同步方法即可搞定的事,但在PHP中却没有好的解决思路。

在网上搜了搜,有两个办法但都不太好:一个是简单的以进程ID+时间戳,或进程ID+随机数来产生近似的唯一ID,虽简单但对于追求“完美”的我不愿这样凑合,再说Apache2以后进程会维持相当长得时间,生成的ID发生碰撞的几率还是比较大的;第二个思路是通过Mysql的自增字段,这个就更不能考虑了,效率低不说,我的设计里压根就没数据库。

递增ID的获取是个过程:

1. 从全局某个存储中读取ID

2. 给ID加1

3. 将ID重新存入全局存储

在多进程或线程的程序中需要将上述3步作为单步的原子操作,才能保证ID的唯一。

Java中很好解决,这是因为Java程序大多以多线程方式运行,每个线程都能共享Java进程中的变量,并能方便的加线程锁控制线程的运转同步。在PHP中ID全局存储没问题,可以放在session中,大不了放在文件中,但进程间同步就是问题了。

实际上进程调度、管理是操作系统内核必须实现的功能,今天介绍的信号量(也称为信号灯)就是在Unix/Linux上解决进程同步的一项技术。

信号灯原是用在铁路上的管理机制,我们今天看到的铁路大多是双线并行,但有的路段受山势、地形影响只有单条铁轨,必须保证同一时间只能有一列火车运行通过这些路段。早先铁路上就是用信号灯来管理的:没有火车经过时,信号等处于闲置状态,一旦有火车进入此路段,信号灯即变为在用状态,其他的火车经过时就需要等待,等待先前的火车驶出路段信号等变为闲置后,才能进入此路段,一旦又有火车进入,信号灯又变为繁忙......,以此来保障铁路运行的安全畅通。

Unix系统就像铁路管理局控制信号灯一样管理控制信号量的状态,因此也可以这样说信号量是由内核管理的,信号量不仅能控制进程间的同步,同样可以控制线程间的同步。

信号量属于系统进程间通讯技术(IPC),今天我们只从PHP角度介绍信号量的使用,有关IPC的技术细节可参考Stevens的权威著作《UNIX网络编程第二卷 进程间通信》。

先看最终的代码:

// ---------------------------------------------------

// 递增序列号ID(1~1000000000)

//

// ID存储在共享内存中(shared memory),通过信号灯(semaphore)同步

// ---------------------------------------------------

$IPC_KEY = 0x1234; //System V IPC KEY

$SEQ_KEY = "SEQ"; //共享内存中存储序列号ID的KEY

//创建或获得一个现有的,以"1234"为KEY的信号量

$sem_id = sem_get($IPC_KEY);

//创建或关联一个现有的,以"1234"为KEY的共享内存

$shm_id = shm_attach($IPC_KEY, 64);

//占有信号量,相当于上锁,同一时间内只有一个流程运行此段代码

sem_acquire($sem_id);

//从共享内存中获得序列号ID

$id = @shm_get_var($shm_id, $SEQ_KEY);

if ($id == NULL || $id >= 1000000000)

{

$id = 1;

}

else

{

$id++;

}

//将"++"后的ID写入共享内存

shm_put_var($shm_id, $SEQ_KEY, $id);

//释放信号量,相当于解锁

sem_release($sem_id);

//关闭共享内存关联

shm_detach($shm_id);

echo "序列号ID:{$id}";

?>

009行,定义了一个16进制的整形KEY,在PHP中只支持System V的IPC机制,需要通过一个KEY关联到指定的资源(消息队列、信号量、共享内存)。

010 行,定义了一个在共享内存中存储递增ID的KEY,这是PHP对System V共享内存的闲置:需要通过类似hashtable的KEY-VALUE方式存储变量。在上面的代码中使用共享内存做ID的存储容器,也可以换为 Session、文件等其他机制,本文重点是信号量,有关共享内存的知识以后在讲(别忘了前面推荐的那本书)。

013行,获得系统中的以1234为KEY的信号量,如果系统中没有就创建一个。

015行,同13行相似,获得系统中的以1234为KEY的共享内存,如果系统中没有就创建一个,第二个参数64表示创建64bytes大小的共享内存。

018~034 行,同步代码区,当一个进程或线程执行sem_acquire函数占有了信号量,到它调用sem_release函数释放信号量的过程内,其他进程或线程执行到sem_acquire会阻塞。021行从共享内存中获得ID,函数shm_get_var前缀"@"是为了屏蔽出错信息(第一次执行时,共享内存中并没有以"SEQ"为KEY的数据,会在页面上打印警告信息)。

其他语句非常简单,不需多讲。

程序编好后,访问这个PHP页面,会递增的输出数字。

我们可以通过系统命令ipcs查看在程序创建的信号量和共享内存:

$ ipcs

------ Shared Memory Segments --------

key shmid owner perms bytes nattch status

0x00001234 1212443 www-data 666 64 0

------ Semaphore Arrays --------

key semid owner perms nsems

0x00001234 163841 www-data 666 3

------ Message Queues --------

key msqid owner perms used-bytes messages

前两段分别是共享内存和信号量,0x00001234既是我们创建的KEY。

也可以通过命令ipcrm删除:

$ ipcrm -M 0x00001234 #删除共享内存

$ ipcrm -S 0x00001234 #删除信号量

---------------------------------------------

PHP手册中关于IPC的资料非常少,这点也不难想象,Stevens已经在十几年前讲得透透的东东,在PHP中只是包装了一下,还有多少必要去深入说明呢?

文本只是借着ID说了说信号量的使用,如果您有更简单的生成自增ID的办法,还望赐教。

可能有朋友还想了解信号量的执行效率,我这里用一句过时的流行语总结: 相当的快。

相关文章

1a1b05c64693fbf380aa1344a7812747.png

这篇文章主要介绍了带你了解PHP7 性能翻倍的关键的相关资料,需要的朋友可以参考下2015-11-11

4f55910a645b073bc4fc65dc10dc14bd.png

这篇文章主要介绍了php实现常见图片格式jpg,png,gif的水印和缩略图制作,使用面向对象方法实现PHP图片水印和缩略图功能,感兴趣的小伙伴们可以参考一下2016-06-06

0ea3c7666119d5615e582f823fb3fad6.png

这篇文章主要介绍了PHP实现ASCII码与字符串相互转换的方法,涉及php字符串的遍历、替换、编码转换等相关操作技巧,需要的朋友可以参考下2017-04-04

4f96a78db829b1556ff16de21e013c7a.png

php 处理上百万条的数据库如何提高处理查询速度2010-02-02

8cc1031babc6aff2319f1c6af8544aa0.png

这篇文章主要介绍了PHP获取photoshop写入图片文字信息的方法,涉及php操作图片的技巧,具有一定参考借鉴价值,需要的朋友可以参考下2015-03-03

0c932a99bb7b6f23c937db507070cc7b.png

这篇文章主要介绍了PHP封装的数据库模型Model类,结合实例形式分析了php基于PDO针对mysql数据库常见增删改查、统计、判断等相关操作封装与使用技巧,需要的朋友可以参考下2019-03-03

cca732bf65a93ed2ec0ac80c638460fe.png

这篇文章主要介绍了php中file_get_contents与curl性能比较,以实例形式详细分析了file_get_contents与curl的区别以及运行效率的对比,需要的朋友可以参考下2014-11-11

2d9f31f2af7b675a3d153d2b7f1035a7.png

下面小编就为大家带来一篇ThinkPHP模板标签eq if 中区分0,null,false的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2017-03-03

b452cee8ec5cd9e58ab98eba17281e59.png

这篇文章主要介绍了PHP快速排序quicksort实现方法,结合实例形式分析了快速排序的原理及php实现快速排序的相关操作技巧,需要的朋友可以参考下2016-09-09

f4838ec7e2d4da28e0b57d4e852dadd4.png

这篇文章主要给大家介绍了关于如何利用PHP实现上传图片功能的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-09-09

最新评论

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值