蘭陵N梓記

一指流沙,程序年华


  • 首页

  • 归档

  • 关于

  • 搜索
close

Go语言不足

时间: 2016-07-18   |   分类: 技术     |   阅读: 2083 字 ~5分钟

最近公司是在疯狂地推广Go语言,我也是推广小组成员。Go语言的确很多的优点,这里并不想表扬Go语言,而是说说它的不足。

生态不成熟

一个语言的流行,都有其背后的推动者。Go语言是由Google公司创建与推动。最近我司的高层也亲自拜访了Go语言的主创人员。Google称目前已有100+的App从Java转向Go。Google内部主要有三大语言(C++、Java、Python),之前对Go语言的公司内部的政治意义大于它的实际使用。近两年来,语言的战略地位凸显,不断地在推动Go语言的应用。

目前主要使用Go语言的公司是一些创业公司或互联网公司。而这些公司采用Go语言非技术的因素主要有:

  • 公司软件资产积累少,不存在切换其它语言成本,使用Go语言可以轻装上阵;
  • 互联网公司的技术人员流动大,Go语言面向开发简化,招人容易,上手快;

采用Go语言的技术因素主要有:

  • Go语言在语言级通过Goroutine与网络IO的Netpoller的封装,能大在简化高并发的网络应用开发,而互联网的应用都以HTTP、网络通讯应用为主;
  • Go语言标准库丰富,能满足互联网应用的常用应用场景:不需要太多的业务逻辑,偏网络接入;

Go当前很多的第三方开源框架,库都是最近一到两年内才诞生的,并且后面没有相应的大公司支撑,个人或小团体的维护的项目居多。这些框架,库的成熟需要时间来锤炼与稳定。

动态扩展机制不成熟

对于编译型静态语言,需要有一种机制来支持动态扩展。C/C++是通过动态库来扩展,Java是支持Class动态加载,或基于JVM平台的其它脚本语言互通。Go语言长期没有支持动态库,Go语言的创始人曾明确表态:

动态库的存在是一个系统的设计Bug

但是在Go1.5版本又加入了动态库支持,对动态库支持采用一定的妥协,这也说明它确有它的应用场景。但目前只支持:Linux/AMD64,ARM平台(cgo·golang/go Wiki,WindowsDLLs·golang/go Wiki)。同时支持也是有限制:

  • Go语言代码,可以生成动态库给C代码调用,也可能给Go代码调用,但他们使用也有区别,参考:Go1.5生成动态库
  • 不支持运行时在代码中动态加载库

目前可行的解决方案:

  • 生成C语言动态库:通过动态加载生成C语言动态库,实现动态扩展,一个进程中,运行了多个“Go世界”(Go的Runtime)
  • 这需要GCC编译器,所以严格来说并不支持Win下的纯DLL动态库(cywin之类的gcc没有验证过)
  • 嵌入脚本语言,实现功能逻辑的动态扩展。
  • 目前开源项目已有纯Go实现的Lua VM,也有通过CGo绑定C的Lua。也有开源项目通过Cgo绑定支持Python,Ruby等;
  • 自创脚本脚本,或DSL脚本,采用Go来实现脚本解释。但如果对性能要高要求,需要支持对脚本的JIT,这是相当有难度,目前也未见有解决方案。
  • 实现基于通信机制的插件模式
  • 类似于VScode的语言服务插件机制,参考:通用语言协议
  • 这本质是进程间的通讯,并不传统意义上的插件扩展机制。

不支持泛型

泛型是目前高级语言最常见的语言基础,Java1.5采用擦除法的泛型(并不像C++一样的Template技术)也解放了不少生产力,能大大减少相似的代码。而Go语言官方团队相对是“民主集中制”,很难听取社区的意见,认为这个总是不紧急,并且他们也没有找到满意的实现方式(C++/Java实现方式都不让他们满意:C++是编译期间展示,生成不同的代码,对编译速度与生成文件大小都有影响;而Java是擦除法,只是语法糖,生成Bytecode变成Object对象,并没有本质变化)。

从目前来看,Go语言在1.0规范发布之后,语法特性几乎没有什么变化,围绕是性能优化与跨平台支持。至少在Go2.0之前,极可能不会引入这个语言特性。

目前可行的解决方案

  • interface{}
  • 类似于C的void*,Java的Object,但这会增加代码的可读性差与安全危险,又与Go的简单哲学不相符
  • Go generate
  • 参考:Golang generate 草案
  • Go泛型编程库:gen
  • gen 项目目的是为 Go 语言带来了类似泛型的函数,灵感来自 C# 的 LinQ 和 JavaScript 的 Array methods 以及 underscore 库。操作包括过滤、分组、排序等等。

Goroutine性能陷阱

Goroutine简化了并发编程,但它并不能消除并发问题(资源竞争,原子性操作),只是把线程的调度预置到了它的Runtime中,让上层应用代码变得很少。它的坑也主要体现在它的调度不可控制上。

下面阻塞不会创建新的调度线程:

  • 网络IO阻塞
  • Channel阻塞
  • Sleep,同步锁阻塞
  • 基于底层系统异步调用的Syscall

下面阻塞会创建新的调度线程:

  • 磁盘IO阻塞
  • CGo方式调用C语言动态库中的调用IO或其它阻塞

这些情况下会导致线程数量爆涨,从而导致系统性能下降,而Goroutine通过go func就能产生一个Goroutine,犯错的成本低,容易被滥用。这需要开发人员熟悉Goroutine内部机制,并小心地避开这些坑。期待Go官方将来能重点解决这些问题。

参考:
[1] goroutine背后的系统知识
[2] golang的goroutine是如何实现的
[3] goroutine与调度器

#go#
为什么是Go
Go语言在线书籍收集
微信扫一扫交流

标题:Go语言不足
作者:兰陵子
关注:lanlingthink(览聆时刻)
声明:自由转载-非商用-非衍生-保持署名(创作共享3.0许可证)

  • 文章目录
  • 站点概览
兰陵子

兰陵子

Programmer & Architect

164 日志
4 分类
57 标签
GitHub 知乎
    • 生态不成熟
    • 动态扩展机制不成熟
    • 不支持泛型
    • Goroutine性能陷阱
© 2009 - 2022 蘭陵N梓記
Powered by - Hugo v0.101.0
Theme by - NexT
0%