You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP中json_encode比Avro编码器更快?基准测试存疑求解

问题:Avro序列化速度远慢于JSON的原因排查

所有资料都显示Avro编码比JSON更快,但实际测试中JSON序列化速度始终远超Avro,这是为什么?

我的测试代码

Avro序列化方法

public function serialize(array $documentArray)
{
    $this->schemaID = 1;
    $parsedSchema = AvroSchema::parse(SCHEMA);

    // 检查本地缓存中是否已有io datum writer,有则复用
    if (isset($this->ioDatumWriterCache[$this->schemaID])) {
        $datumWriter = $this->ioDatumWriterCache[$this->schemaID];
    } else {
        $datumWriter = new \AvroIODatumWriter($parsedSchema);
        $this->ioDatumWriterCache[$this->schemaID] = $datumWriter;
    }

    // 检查本地缓存中是否已有binary encoder,有则复用
    if (isset($this->binaryEncoderCache[$this->schemaID])) {
        $encoder = $this->binaryEncoderCache[$this->schemaID];
    } else {
        $encoder = new \AvroIOBinaryEncoder($this->ioWriter);
        $this->binaryEncoderCache[$this->schemaID] = $encoder;
    }

    $datumWriter->write($documentArray, $encoder);

    return $this->ioWriter->string();
}

JSON序列化方法

public function serialize(array $documentArray): string
{
    try {
        return json_encode($documentArray, JSON_THROW_ON_ERROR);
    } catch (\Exception $ex) {
        throw new ObjectIOException('JSON decode exception', 0, $ex);
    }
}

测试结果(使用phpbench)

  • JSON编码平均耗时:
    1.685μs、1.642μs、1.637μs、1.642μs、1.637μs
  • Avro编码平均耗时:
    40.574μs、40.716μs、40.664μs、40.480μs、40.583μs

问题原因与优化方案

1. Schema重复解析是核心开销

你的代码每次调用serialize都会执行AvroSchema::parse(SCHEMA),Schema解析是CPU密集型操作,哪怕缓存了Writer和Encoder,这一步的重复执行会吃掉大量性能。必须将Schema解析移到类初始化阶段,只执行一次。

2. PHP Avro与JSON的实现差异

json_encode是PHP底层的C语言实现,性能极高;而PHP的Avro库大多是纯PHP实现,本身在执行效率上就有先天差距。Avro的优势更多体现在:

  • 大数据量、重复序列化相同结构数据的场景
  • 跨语言兼容性
  • 序列化后的数据体积更小(二进制格式)
    小数据量下,纯PHP实现的Avro很难打过原生C实现的JSON。

3. IO Writer未重置导致的额外开销

如果$this->ioWriter没有在每次序列化前重置状态,会导致缓冲区累积之前的数据,增加后续写入和读取的开销。每次序列化前需要调用$this->ioWriter->rewind()清空缓冲区。

4. 缓存逻辑的有效性验证

确认测试时使用的是同一个类实例多次调用serialize,如果每次测试都新建类实例,缓存的Writer和Encoder就无法复用,会重复初始化带来额外开销。

优化后的Avro序列化代码示例

public function __construct()
{
    // 初始化阶段只执行一次Schema解析
    $this->schemaID = 1;
    $this->parsedSchema = AvroSchema::parse(SCHEMA);
    
    // 提前初始化并缓存Writer
    $this->ioDatumWriterCache[$this->schemaID] = new \AvroIODatumWriter($this->parsedSchema);
    
    // 初始化可复用的IO Writer
    $this->ioWriter = new \AvroStringIO();
    // 缓存Encoder
    $this->binaryEncoderCache[$this->schemaID] = new \AvroIOBinaryEncoder($this->ioWriter);
}

public function serialize(array $documentArray)
{
    // 重置IO Writer,清除上次序列化的残留数据
    $this->ioWriter->rewind();
    
    $datumWriter = $this->ioDatumWriterCache[$this->schemaID];
    $encoder = $this->binaryEncoderCache[$this->schemaID];

    $datumWriter->write($documentArray, $encoder);

    return $this->ioWriter->string();
}

额外测试建议

  • 测试更大的数据集(比如包含数百字段的复杂结构,或批量序列化数千条数据),观察Avro的性能表现是否会提升
  • 对比序列化后的数据体积,Avro的二进制格式通常比JSON小30%-50%,这也是它的核心优势之一
  • 确保测试时复用同一个类实例,让缓存逻辑真正生效

内容的提问来源于stack exchange,提问作者HerbertRedford

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 03:23:15