dragon2025 2015-02-23 00:50
浏览 22
已采纳

有没有一种方法可以使用编码/目标序列化循环数据结构?

I'm working on porting a neural network library to Go. I want to be able to save and restore a trained network, so I'm attempting to serialize it directly. The problem is, the network struct contains cycles in its field (Neuron A has a connection to Neuron B, which has a connection to Neuron A). Whenever I try to serialize the entire network with encoding/gob, it fails with a stackoverflow.

Here's a very simple example of code that breaks in the same way:

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
    "log"
)

type P struct {
    Name    string
    Q *Q
}

type Q struct {
    Name string
    P *P
}

func main() {
    var network bytes.Buffer        // Stand-in for a network connection
    enc := gob.NewEncoder(&network) // Will write to network.
    dec := gob.NewDecoder(&network) // Will read from network.

    p := &P{ "P", nil }
    q := &Q{ "Q", p }
    p.Q = q

    err := enc.Encode(p)
    if err != nil {
        log.Fatal("encode error:", err)
    }
    // Decode (receive) the value.
    var p2 *P
    err = dec.Decode(&p2)
    if err != nil {
        log.Fatal("decode error:", err)
    }
    fmt.Printf("%#v", p2)
}

http://play.golang.org/p/LrO0VlLnX4

Barring rewriting the entire structure of the library to avoid cycles, is there a straightforward way to get around this problem?

Thanks

  • 写回答

1条回答 默认 最新

  • doushi4956 2015-02-23 01:56
    关注

    You can't use gob directly, but fear not brave citizen of the world!

    You can implement the BinaryMarshaler/BinaryUnmarshaler interfaces on your type as a work around and gob will happily use them instead when it's encoding/decoding your type.

    func (p *P) MarshalBinary() (_ []byte, err error) {
        var buf bytes.Buffer
        enc := gob.NewEncoder(&buf)
        enc.Encode(p.Name)
        if p.Q == nil {
            return buf.Bytes(), nil
        }
        isCyclic := p.Q != nil && p.Q.P == p
        enc.Encode(isCyclic)
        if isCyclic {
            p.Q.P = nil
            err = enc.Encode(p.Q)
            p.Q.P = p
        } else {
            err = enc.Encode(p.Q)
        }
        //buf.Encode
        return buf.Bytes(), err
    }
    
    func (p *P) UnmarshalBinary(data []byte) (err error) {
        dec := gob.NewDecoder(bytes.NewReader(data))
        if err = dec.Decode(&p.Name); err != nil {
            return
        }
        var isCyclic bool
        if err = dec.Decode(&isCyclic); err != nil {
            return
        }
        err = dec.Decode(&p.Q)
        if isCyclic {
            p.Q.P = p
        }
        return
    }
    

    <kbd>playground</kbd>

    warning creating a new decoder/encoder every time is extremely inefficient, you might want to look into using binary.*.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题