Python is Easy. Go is Simple. Simple != Easy

简介: Python以其易学易用著称,常用于初学者编程和复杂科学计算,但其解释器的复杂性和环境易变性可能导致运行时问题。Go语言则追求简单,语法稳定,编译快速,生成的二进制文件小巧、独立。Go的静态链接特性使其能在不同系统上无缝运行,而Python在数据科学和原型设计上仍具有优势。结合两者,通过Django进行快速原型验证,然后用Go重构业务逻辑和高性能部分,形成了一种有效的开发策略。

简介

Python 和 Go 具有独特的品质,可以相辅相成。

有一个常见的误解,认为“简单”和“容易”指的是同一件事。毕竟,如果某样东西易于使用,那么它的内部工作原理也一定很容易理解,对吧?或者相反也是一样?事实上,情况恰恰相反。虽然这两个概念指向相同的结果,但要让事情看起来简单,背后需要巨大的复杂性。

以Python为例,这种语言因其低入门门槛而闻名,因此成为编程入门的首选语言。全球各地的学校、大学、研究中心和大量企业都选择了Python,因为无论人们的教育水平或学术背景(或完全没有)如何,任何人都可以使用它。

人们很少需要太多类型理论或了解事物如何及其在内存中的存储位置、运行某些代码的线程等等。此外,Python是通往一些最深奥的科学和系统级库的入门门户。能够用一行代码控制如此强大的功能,在很大程度上有助于它成为最流行的编程语言之一。

但问题来了——用Python代码表达事物的便捷性是有代价的。在底层,Python解释器非常庞大,即使是一行代码也必须执行许多操作才能运行。当您听到有人将Python称为“慢”语言时,大部分感知到的“慢”来自解释器在运行时做出的决策数量。

但在我看来,这还不是最大的问题。Python运行时生态系统的复杂性,加上围绕其包管理的一些自由设计决策,导致环境非常脆弱,更新通常会导致不兼容和运行时崩溃。让Python应用程序在几个月后返回到它,却发现主机环境已经发生了足够的变化,甚至不再可能启动该应用程序,这种情况并不罕见。

当然,这过于简单化了问题,甚至现在的孩子都知道容器的存在就是为了解决这样的问题。事实上,借助Docker及其类似工具,我们可以及时“冻结”Python代码库的依赖项,使其实际上可以永远运行。然而,这是以将责任和复杂性转移到操作系统基础设施为代价的。

从轻松到简单

如果我们使用Python来解决这些问题,我们最终会得到类似于Rust的东西——性能极高,但入门门槛也非常高。

在我看来,Rust不易使用,也不简单。尽管它现在完全被炒作了,我虽然拥有20年的编程经验,并且已经在C和C++中迈出了第一步,但我无法在看到一段Rust代码后就确信我理解了其中发生的事情。

大约五年前,当我在开发基于Python的系统时,我发现了Go。虽然我尝试了几次才开始喜欢这种语法,但我立刻就爱上了这种简单的理念。Go的目标是让组织中的任何人都能简单地理解——从刚从学校毕业的初级开发者到偶尔查看代码的高级工程经理。

更重要的是,作为一种简单的语言,Go很少进行语法更新——最后一个重要的更新是在v1.18中添加泛型,这是经过十年认真讨论的结果。在大多数情况下,无论您是查看五天前还是五年前编写的Go代码,它基本上都是相同的,并且应该可以正常工作。

然而,简单需要纪律。一开始可能会感觉受限,甚至有些落后。特别是与Python中的简洁表达式相比,例如列表或字典理解:

temperatures = [
    {
   
   "city": "City1", "temp": 19},
    {
   
   "city": "City2", "temp": 22},
    {
   
   "city": "City3", "temp": 21},
]

filtered_temps = {
   
   
    entry["city"]: entry["temp"] for entry in temperatures if entry["temp"] > 20
}

Go 中的相同代码需要更多的击键,但理想情况下应该更接近 Python 解释器在幕后所做的事情:

type CityTemperature struct {
   
   
    City      string
    Temp float64
}

// ...

temperatures := []CityTemperature{
   
   
    {
   
   "City1", 19},
    {
   
   "City2", 22},
    {
   
   "City3", 21},
}

filteredTemps := make(map[string]float64)
for _, ct := range temperatures {
   
   
    if ct.Temp > 20 {
   
   
        filteredTemps[ct.City] = ct.Temp
    }
}

虽然 Python 能够编写出功能等同的代码,但编程领域内一条不言而喻的原则是,如果某种语言提供了更为简洁(无论是在简洁性还是优雅性方面)的解决方案,程序员往往会偏好使用该语言。然而,简洁性是主观的,并且理应对每个程序员都具有相同的适用性。可供选择的执行相同操作的替代方法促成了多样化的编程风格,而在同一代码库中发现多种风格的情形并不罕见。

Go 语言因其冗长和“乏味”的特性,自然而然地满足了另一项需求——Go 编译器在编译可执行文件时所需完成的工作量远远小于其他语言。编译并运行 Go 应用程序的速度通常与启动 Python 解释器或 Java 虚拟机一样迅捷,甚至更快。毫不夸张地说,Go 程序的启动速度几乎与本地可执行文件一样快。尽管其速度不及 C/C++ 或 Rust 的程序,但其代码复杂度却只是后两者的一小部分。

我愿意对 Go 的这一小“瑕疵”视而不见。最后但同样重要的是,Go 二进制文件是静态链接的,这意味着你可以在任何地方构建它,然后在目标主机上运行——无需任何运行时或库的依赖。为了便利,我们仍然会将 Go 应用程序打包进 Docker 容器中。即便如此,它们的体积依然要小得多,同时在内存和 CPU 消耗方面也仅占 Python 或 Java 同类产品的一小部分。

Python + Go

我们在工作中发现的最务实的解决方案是将Python的易用性与Go的简单性结合起来。

对我们而言,Python是一个极佳的原型设计平台,它不仅是思想诞生的地方,也是科学假设被验证或否定的场所。Python特别适合于数据科学和机器学习领域,鉴于我们需要处理大量此类任务,尝试用其他工具重新发明轮子显得毫无意义。

Python还是Django的核心,后者的宗旨是允许像使用其他工具一样快速开发应用程序(当然,这里也值得一提的是Ruby on Rails和Elixir的Phoenix)。假设一个项目需要进行一些用户管理和内部数据管理(正如我们大多数项目所需)。在这种情况下,我们会选择从Django框架开始,因为它内置了Admin功能,这非常方便。

一旦Django的初步概念验证开始呈现出产品形态,我们就会评估有多少部分可以用Go重写。由于Django应用程序已经定义了数据库结构以及数据模型的形态,因此在其基础上编写Go代码变得十分容易。经过几轮迭代后,我们建立了一种共生关系,双方在同一数据库上和平共存,并通过基本的消息传递机制进行交流。最终,Django“壳”充当了协调者的角色——它负责我们的管理需求并触发任务,然后由Go的对应部分来处理。Go部分则负责其他所有事务,从前端API和端点到业务逻辑和后端作业处理。

到目前为止,这种共生关系运行良好,我希望未来也能继续保持。

相关文章
|
7天前
|
Rust 安全 程序员
|
12天前
|
前端开发 Java Go
开发语言详解(python、java、Go(Golong)。。。。)
开发语言详解(python、java、Go(Golong)。。。。)
|
5月前
|
Go 云计算 开发者
2024 Python开发者转型Go开发
随着Go语言在云计算、微服务和高性能网络服务中的流行,Python开发者面临是否转向Go开发的选择。这个决定涉及到多方面的考量,包括语言特性、生态系统、性能需求、学习曲线和职业发展等。本文将深入探讨Python开发者转向Go开发的利弊,分析两种语言在不同场景下的适用性,并提供从Python到Go的过渡策略,旨在为Python开发者提供全面的转型指南。
57 0
2024 Python开发者转型Go开发
|
9月前
|
Rust 自然语言处理 Java
单链表的多语言表达:C++、Java、Python、Go、Rust
单链表是一种链式数据结构,由一个头节点和一些指向下一个节点的指针组成。每个节点包含一个数据元素和指向下一个节点的指针。头节点没有数据,只用于表示链表的开始位置。单链表相对于数组的优点是插入和删除元素时不需要移动其他元素,时间复杂度为O(1)。但是,在查找元素时,单链表比数组要慢,时间复杂度为O(n)。
16640 7
|
5月前
|
Cloud Native Linux Go
Go 编程语言详解:用途、特性、与 Python 和 C++ 的比较
Go是一个跨平台、开源的编程语言 Go可用于创建高性能应用程序 Go是一种快速、静态类型、编译型语言,感觉上像动态类型、解释型语言 Go由Robert Griesemer、Rob Pike和Ken Thompson于2007年在Google开发 Go的语法类似于C ++
74 0
|
5月前
|
Go Python
go cmd 使用 与 结构 说明,go cmd 调用 python
go cmd 使用 与 结构 说明,go cmd 调用 python
28 0
|
6月前
|
JavaScript 程序员 Go
一图看懂编程语言迁移模式:终点站是Python、Go、JS
一图看懂编程语言迁移模式:终点站是Python、Go、JS
|
9月前
|
存储 Go Python
分别用python和go语言来实现的风靡一时的2048 游戏,包含完整代码
@[TOC](目录) 2048 游戏实现主要包括以下几个步骤: 1. 创建一个棋盘,通常使用二维列表表示。 2. 实现棋子的移动规则,左移、右移、上移、下移。 3. 判断游戏是否结束,即棋盘是否已满或者无空位可移动。 4. 实现游戏界面的显示。 # 1、Python实现 下面是一个简单的 Python 实现示例,运行效果如下: ```python import pygame import sys import random # 初始化 pygame pygame.init() # 设置屏幕大小 screen_size = (80
126 0
|
12月前
|
Shell Go 数据安全/隐私保护
Go/Python 免杀
Go/Python 免杀
|
12月前
|
JSON 编译器 Go
人们都在说Go=C+Python,有必要先学个入门再说对不对2
人们都在说Go=C+Python,有必要先学个入门再说对不对
52 0