我很好奇,PHP中的序列化是否有大小限制。是否可以使用5,000个键和值序列化数组,以便将其存储到缓存中?
我希望在社交网站上缓存用户朋友列表,缓存需要经常更新,但几乎每个页面加载都需要读取。
在单个服务器设置上,我假设APC会比memcache更好。
答案 0 :(得分:27)
正如其他几个人已经回答的那样,只是为了好玩,这是一个非常快速的基准(我敢称之为吗?);请考虑以下代码:
$num = 1;
$list = array_fill(0, 5000, str_repeat('1234567890', $num));
$before = microtime(true);
for ($i=0 ; $i<10000 ; $i++) {
$str = serialize($list);
}
$after = microtime(true);
var_dump($after-$before);
var_dump(memory_get_peak_usage());
我在PHP 5.2.6(与Ubuntu jaunty捆绑的那个)上运行它。
而且,是的,只有价值观;没钥匙;而且值非常简单:没有对象,没有子数组,只有字符串。
对于$num = 1
,您会得到:
float(11.8147978783)
int(1702688)
对于$num = 10
,您会得到:
float(13.1230671406)
int(2612104)
而且,对于$num = 100
,你得到:
float(63.2925770283)
int(11621760)
所以,似乎数组的每个元素越大,它需要的时间就越长(看起来很公平,实际上)。但是,对于100倍大的元素,你不需要花费100倍的时间......
现在,使用50000个元素的数组,而不是5000,这意味着这部分代码已更改:
$list = array_fill(0, 50000, str_repeat('1234567890', $num));
使用$num = 1
,您将获得:
float(158.236332178)
int(15750752)
考虑到1花费的时间,我不会为$ num = 10或$ num = 100运行此...
是的,当然,在真实的情况下,你不会这样做10000次;所以让我们只尝试for循环的10次迭代。
$num = 1
:
float(0.206310987473)
int(15750752)
$num = 10
:
float(0.272629022598)
int(24849832)
对于$num = 100
:
float(0.895547151566)
int(114949792)
是的,这几乎是1秒 - 并且使用了相当多的内存^^
(不,这不是生产服务器:我在这台开发机器上有一个相当高的memory_limit ^^)
所以,最后,要比那些数字稍微短一点 - 是的,你可以让数字说出你想要的任何数字 - 我不会说有一个“限制”就像在PHP中的“硬编码”一样,但你最终会遇到其中一个:
max_execution_time
(通常,在网络服务器上,它不会超过30秒)memory_limit
(在网络服务器上,通常不超过32MB)但是,除非你真的在序列化长数据大数据,否则我不确定它会那么重要......
您必须考虑使用该缓存可以帮助您获得的时间/ CPU负载量; - )
然而,最好的方法是用自己的真实数据进行测试; - )
答案 1 :(得分:7)
serialize()功能仅受可用内存的限制。
答案 2 :(得分:5)
PHP没有强制执行限制。 Serialize返回序列化结构的字节流表示(字符串),因此您只需获得一个大字符串。
答案 3 :(得分:4)
唯一可行的限制是你的可用内存,因为序列化涉及在内存中创建一个字符串。
答案 4 :(得分:3)
没有限制,但请记住序列化和反序列化有成本。
反序列化成本极高。
缓存数据的成本较低的方法是通过var_export()
本身(因为PHP 5.1.0,它适用于对象):
$largeArray = array(1,2,3,'hello'=>'world',4);
file_put_contents('cache.php', "<?php\nreturn ".
var_export($largeArray, true).
';');
然后,您可以通过执行以下操作来简单地检索数组:
$largeArray = include('cache.php');
资源通常无法缓存。
不幸的是,如果您的数组中有循环引用,则需要使用serialize()
。
答案 5 :(得分:3)
正如以上思想家所建议的那样:
您可以使用
$string = json_encode($your_array_here);
并解码
$array = json_decode($your_array_here, true);
这将返回一个数组。即使编码数组是多级的,它也能正常工作。
答案 6 :(得分:2)
好的...更多数字! (PHP 5.3.0 OSX,没有操作码缓存)
我的机器上的@Pascal代码,在10k时n = 1,产生:
float(18.884856939316)
int(1075900)
我将unserialize()添加到上面。
$num = 1;
$list = array_fill(0, 5000, str_repeat('1234567890', $num));
$before = microtime(true);
for ($i=0 ; $i<10000 ; $i++) {
$str = serialize($list);
$list = unserialize($str);
}
$after = microtime(true);
var_dump($after-$before);
var_dump(memory_get_peak_usage());
生成
float(50.204112052917)
int(1606768)
我假设额外的600k左右是序列化字符串。
我很好奇var_export及其include / eval伙伴$str = var_export($list, true);
而不是原始产品中的serialize()
float(57.064643859863)
int(1066440)
所以只需要少一点内存(至少对于这个简单的例子),但已经有更多的时间了。
在eval('$list = '.$str.';');
中添加而不是在上面生成
float(126.62566018105)
int(2944144)
表示在执行eval时某处可能存在内存泄漏: - /。
再说一次,这些不是很好的基准测试(我真的应该通过将字符串放在本地var或其他东西中来隔离eval / unserialize,但我很懒)但它们显示了相关的趋势。 var_export似乎很慢。
答案 7 :(得分:1)
不,没有限制,这是:
set_time_limit(0);
ini_set('memory_limit ', -1);
unserialize('s:2000000000:"a";');
为什么你应该安装safe.mode = On或像Suhosin安装的扩展程序,否则会占用你系统中的所有内存。
答案 8 :(得分:1)
我认为比序列化更好json_encode函数。它有一个缺点,关联数组和对象没有区别,但字符串结果更小,更容易被人阅读,所以也可以调试和编辑。
答案 9 :(得分:1)
如果你想缓存它(因此我假设性能是问题),请改用apc_add以避免在内存中将其转换为字符串+增益缓存时的性能损失。
如上所述,唯一的尺寸限制是可用内存。
其他一些问题: 序列化数据在多字节和单字节字符编码之间不可移植。 PHP5类包含NUL字节,这些字节可能会导致破坏不期望它们的代码。
答案 10 :(得分:1)
您的用例听起来好像您最好使用数据库来做到这一点,而不是仅仅依靠PHP的可用资源。使用像MySQL这样的东西的优势在于它专门设计了内存管理,用于存储和查找等。
为了更新或更改一些信息,不断地序列化和反序列化数据真的很有趣。
答案 11 :(得分:0)
我有一个案例,其中反序列化会在大型序列化对象上抛出异常,大小:65535(幻数:16位满位= 65536)
答案 12 :(得分:0)
我刚刚遇到一个实例,我认为我达到了序列化的上限。
我使用mysql TEXT
字段将序列化对象持久化到数据库。
单字节字符的可用字符数限制为65,535,因此我可以序列化比PHP更大的对象。由于它们被TEXT
字段的限制截断,因此无法对它们进行反序列化。