当前位置: 首页 > 网络应用技术

由Golang零和GOB库的特征引起的错误

时间:2023-03-09 02:16:21 网络应用技术

  就在今年9月,我负责的部门平台项目发布了新版本。此版本同时具有新功能,这与及时的任务相似。每天,一切都是正常的,但是第二天,很少有未正常执行的任务(暂停暂停的任务,并且未执行正常任务)。

  问题的现象引起了我的第一个反应,另一个同事认为正时任务的逻辑有问题。但是,在我们花费大量时间检查和测试之后,问题的基础不是功能逻辑,而是一个已经启动了一年的公共法规的基本公共法规。该代码的核心是本文的主角。问题的根本原因是语言的特征:零值。

  在下面的文章中,我将在更简单的示例中描述此错误。

  让我们简要介绍零值。

  零值是GO语言中的特征。简而言之,GO语言将为未分配的某些变量提供默认值。例如,以下代码:

  零价值确实给开发人员带来了便利,但是许多不喜欢它的人认为零值的存在使该代码并不严格从语法级别上层面并带来一些不确定性。邮政。

  在中国,它是GO语言附带的标准库。实际上,它是缩写的,因此我们也可以从名称中猜测,并且应该与二进制有关。

  实际上,它是GO语言独有的。该格式已序列化,派生的程序数据与GO语言相似,类似于Python。最常见的用法是订购对象(结构)并将其存储到磁盘文件中。当您需要时,请阅读文件和反应,以应对对象持久性的影响。

  我不会提出示例,本文不是一个主题。这是其官方文件。不熟悉我们的朋友可以查看文档的一部分,或直接阅读我后来文章中描述的示例。

  在本文的开头,我简要描述了问题的起源。在这里,我使用更简单的模型来描述它。

  首先,我们定义一个结构名称:

  围绕这种结构,我们将输入几个人员信息,每个人都是一个对象。但是由于某些原因,我们必须将这些人员的信息用于本地磁盘,而不是MySQL等数据库。

  然后,我们有这样的要求:

  遍历和辨别本地存储的文件,然后判断男人和女人的数量,并计算出来。

  根据上述需求和背景,代码如下(为了节省空间,此处省略了代码):

  执行代码后,我们得到了此结果:

  嗯1个女人,4个男人?当它出现时,这个结果显然与我们的预设数据不一致。哪里有问题?

  我们在函数中的循环中添加一行打印语句,读取我们读取的对象,然后获得这样的结果:

  好人,珍妮和结婚都成为男人!但是神奇的是,除了这个项目之外,所有其他数据都是正常的!看到这个结果,如果您像我一样,您经常处理诸如JSON和YML之类的配置文件,很可能是您认为上述GOB文件是正常读取的,并且应该存储问题。

  但是该文件是一个二进制文件,我们很难像JSON文件一样用肉眼验证。任何工具(例如Linux下)只能获得如此模棱两可的输出:

  也许我们可以尝试几乎没有分析这些二进制文件以比较它们之间的差异;或两个对象的背面序列化除了文件的相同对象,然后比较。如果您有兴趣,可以尝试。在那个时候,我们没有因时间紧迫和其他原因而尝试这种方法,但已修改继续测试的数据。

  因为上述问题中的两个数据是女性,所以程序员的直觉告诉我,这可能不是巧合。因此,我试图修改数据顺序,将男性和女人完全分开,然后进行了测试:

  出现了悖论的现象。当雌性首先,然后是男人时,一切正常。当男人和女人通常是正常的,女人不正常。甚至Mia的原始0 ID也成为2!

  在重复测试和观察结果集后,我们得出了一个定期的结论:所有男性数据都是正常的,所有问题都是女性数据!

  进一步描述此结论的公式:如果先前的数据为non -0数字,并且背面的数据编号为0,则随后的0将被其前面的non -0覆盖。

  审计程序代码再次,我注意到这句话:

  为了保存其他新对象的开销,我使用了相同的变量来循环文件中的数据并做出一个性别判断。用我们之前发现的错误规则进行了审判,答案似乎与之接近:SO SO- 以前的数据0由上一个non -0涵盖,这很可能会使用相同的对象加载文件导致先前的数据残基。

  验证方法也很简单。您只需要将该公共对象放在下面的循环中,以便重新创建每个周期以加载文件数据以切断先前数据的效果。

  让我们修改代码(省略了额外的部分):

  正确的!

  结果的确是我们认为数据残留的原因。但是这里还有另一个问题:为什么读取旧方法读取是正常的数据?除了会受到0的影响,其他数字(年龄)不会被影响?

  现在所有的问题似乎都指向0的特殊编号!

  在此之前,我们最终注意到了零值的特征。因此,我迅速阅读了图书馆的官方文件并找到了这样的句子:

  如果字段的类型为零值(数组除外;请参见上文),则将其从传输中省略。

  翻译:

  如果字段的类型为零值(数组除外),则将在传输过程中省略。

  这句话的前后文章在说,因此与本文中的示例相一致。

  根据我们提前得出的结论和官方文件,我们最终可以完全得出结论:

  当库操作数据时,它将忽略数组之外的零值。我们的代码最初使用公共对象来加载文件数据。由于未传输零值,因此将不会读取原始数据中零值的字段。我们看到的实际上是先前的非零值。对象数据。

  解决方案也很简单,也就是说,我在它上做到了,只是不要使用公共对象加载。

  在我在项目错误中描述的文章的开头中,我使用0和1表示正时任务的状态(悬架,运行)。就像上面一样,不同的任务受到零值问题的干扰,这会导致异常任务执行,以及其他不涉及零值的领域是正常的。尽管它是一个在线生产环境,但幸运的是,发现的问题很早,并且时间上的处理并未引起任何生产事故。但是整个过程和最终答案是深层的我的脑海里印在我的脑海中。

  后来,我与同事讨论。我为什么选择忽略零值?从我的角度来看,可能是节省空间。我们在开始时编写的代码还创建了一个公共对象来节省空间。结果,两个空间储蓄逻辑的逻辑最终与隐藏的错误相撞。