Jun15

【原创】PHP取模时为负数小计

Author: leeon  Click: 4161   Comments: 0 Category: php  Tag: php,取余数

      用了几年的php今天才注意到在32位环境下php去大数字取模为负数情况存在。在32位php运行环境下,被取模的数字不能大于数字2147483648,除了php手册中说明的采用fmod函数的方式获取正确数值外,现在大部分的服务器已经是64位话,在php编译为64位运行时时,是可以正常支持到更大的取模运算,这时候当数值大于2147483647时取模是不会出现负数的。也就是说当我们php运行在64位环境下同时编译的php为64位版本一般不会出现负数问题,除非你的被取模数字大于9223372036854775808,此时已经超过有符号64位的最大取值范围了。

    注意如果取模数值超过了64位的最大整型值,这时候取模得到的数值都为0。如果更大的数值取模保险的方式还是使用fmod函数,

Nov5

【原创】在zend studio中添加第三方库

Author: leeon  Click: 5232   Comments: 0 Category: php  Tag: php,pecl,zend studio

好久没碰PHP了,最近温习一下,下载了最新版的zendstudio来体验。在编写引用第三方库的接口时,zendstudio往往不会那么智能,导致无法自动提示代码,和代码检查。zendstudio本身就是eclipse二次开发的,可以支持到include path的配置。那么我们使用pecl的memcached第三方库做为示例来讲解如果在我们的PHP工程中正常调用第三方库接口。

下载pecl的memcached第三方库,解压目录后可以获取到memcached-api.php文件,这个就是此扩展的接口定义。我们将此文件放入新创建定义的third目录下。

配置libraries: 点击选择windows-> preferences ->PHP-> Libraries 

点击New新增:输入库名,这里我们统一定义一个第三方库集合。勾选add to environment。

新增后,选择新增项然后点击add external folder ,这时候会弹出目录选择窗口,选择关联到先前创建的third目录。

创建好libraries后还是不够的,我们需要在工程中进行关联:

选择工程点击右键,选取include path -> Configure include path 

在选项卡中选择Libraries,然后点击Add Library ,在弹出的窗口中选择刚才我们创建的third 即可。

此时在我们的工程中就可以正常引用第三方库了。

备注: 通常在pecl的扩展包中都会有一个php接口文件,我们添加接口扩展都可以用到此文件。




May22

【原创】PHP扩展模块memcached长连接使用方法介绍

Author: leeon  Click: 10004   Comments: 1 Category: php  Tag: php,memcached

      网上广泛流传着一篇文章,讲述php的两个扩展模块memcache和memcached的区别,其中特意强调了memcached与memcached一个很大的区别是memcached模块不支持长连接。以至于后来很多年我都认为memcached是不支持长连接的,其实不然,memcached扩展模块从很早的版本开始就已经支持长连接了。从扩展模块的源码注视中我们就能看到:

/* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]]))

   Creates a Memcached object, optionally using persistent memcache connection */

static PHP_METHOD(Memcached, __construct)

{

从php的手册身上我们可以看到memcached的扩展模块提供的构造函数提供一个参数persistent_id可选项,手册中这样介绍:

      默认情况下,Memcached实例在请求结束后会被销毁。但可以在创建时通过persistent_id为每个实例指定唯一的ID, 在请求间共享实例。所有通过相同的persistent_id值创建的实例共享同一个连接。 

这个参数的含义就是说如果你传递了一个命名id给到构造方法,那么就会建立长连接,通常我们使用的都是PHP-FPM模式,这样PHP-FPM进程就会和memcached服务简历一条长连接通道。我们也可以理解为persistent_id就是一个连接池名字,所有php-fpm进程都是这个连接池中的一员。

     但我们需要注意的是php是解释性语言,当php第一次通过memached模块建立起长连接后,切记后续的php执行就不要再通过memcached的构造函数构建相同persistent_id命名的长连接,可以建立不同persistent_id名字的长连接,如果是相同的名字被php重复执行,一定会导致php-fpm的进程异常导致与memcached的通信越来越慢,同时根据libmemcached的版本不同还会导致php产生coredump。

    那么我们如何避免单个php-fpm在建立完以persistent_id命名的长连接后不再重复建立长连接呢?其实在PHP带有评注的手册上是有讲解的,内容如下:

When using persistent connections, it is important to not re-add servers.

This is what you do not want to do:
[code="php"]
$mc = new Memcached('mc');
$mc->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$mc->addServers(array(
array('mc1.example.com',11211),
array('mc2.example.com',11211),
));
[/code]
Every time the page is loaded those servers will be appended to the list resulting in many simultaneous open connections to the same server. The addServer/addServers functions to not check for existing references to the specified servers.

A better approach is something like: [code="php"]
$mc = new Memcached('mc');
$mc->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
if (!count($mc->getServerList())) {
$mc->addServers(array(
array('mc1.example.com',11211),
array('mc2.example.com',11211),
));
}
[/code]

通过使用getServerList()方法来检查当前执行使用的php-fpm进程容器中是否已经存在相同名字的长连接资源,如果存在就不要重复使用addServers() 方法来新增长连接配置。

Mar1

【学习笔记】PHP中copy on write写时复制机制

Author: leeon  Click: 5536   Comments: 0 Category: php  Tag: php,写时复制,数组

什么是写时复制(Copy On Write)?

答:在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.这样,在对新的对象执行读操作的时候,内存数据不发生任何变动,直接执行读操作;而在对新的对象执行写操作时,将真正的对象复制到新的内存地址中,并修改新对象的内存映射表指向这个新的位置,并在新的内存位置上执行写操作。

这个技术需要跟虚拟内存和分页同时使用,好处就是在执行复制操作时因为不是真正的内存复制,而只是建立了一个指针,因而大大提高效率。但这不是一直成立的,如果在复制新对象之后,大部分对象都还需要继续进行写操作会产生大量的分页错误,得不偿失。所以COW高效的情况只是在复制新对象之后,在一小部分的内存分页上进行写操作。

     在PHP 内核中同样使用了写时复制机制来避免在赋值时导致内存增加,比如我们在使用foreach循环体时,可以发现其中的奥秘,示例代码:

[code="php"]
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
[/code]

当我们执行此代码时会得到内存占用为:788 

[code="php"]
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as $v){
$count++;
$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
[/code]

当我们取消 //$v='aaaaaaaaaaaaaa';  的注释,此时内存占用数值为:840,注意内存增长了。

[code="php"]
$m1 = memory_get_usage();
$str=<<<EOF
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
aaaaaaaaaaaaaa
EOF;
$arr = explode("\n", $str);
$count=0;
foreach($arr as &$v){
$count++;
//$v='aaaaaaaaaaaaaa';
}
$m2 = memory_get_usage();
echo $m2-$m1;
[/code]


当我们将foreach中的$v 改写为 &$v 时,不管是否注释循环体中对$v的注释,我们都可以得到内存占用为:788

这里就说明了COW机制的介入,当我们在foreach循环中纯粹的只用到对$v 的读操作时,PHP内核会将$v这个变量的内存地址指向到$arr中数组这一索引的内存地址,并没有将数组中的数据复制一份给到变量$v,此时内存占用情况和使用&$v 是一样的。但当我们在循环体内对$v进行写操作时,写时复制机制就被激活了,此时PHP会重新开辟一段内存空间给到$v变量,而将原先$v指向数组的内存地址给断开了,此时内存必然就会增长了。

这里可以得出另外一个结论:当我们在读取大数据的时候,要注意COW机制引入的内存增长影响,同样避免不必要的对变量写,可以提高代码运行性能。

分类

标签

归档

最新评论

Abyss在00:04:28评论了
Linux中ramdisk,tmpfs,ramfs的介绍与性能测试
shallwe99在10:21:17评论了
【原创】如何在微信小程序开发中正确的使用vant ui组件
默一在09:04:53评论了
Berkeley DB 由浅入深【转自架构师杨建】
Memory在14:09:22评论了
【原创】最佳PHP框架选择(phalcon,yaf,laravel,thinkphp,yii)
leo在17:57:04评论了
shell中使用while循环ssh的注意事项

我看过的书

链接

其他

访问本站种子 本站平均热度:8823 c° 本站链接数:1 个 本站标签数:464 个 本站被评论次数:94 次