Golang语言--资源自动回收技术
Go语言作为一个现代化的编程语言以及支持垃圾内存的自动回收特性(GC). 我们现在关注的是非内存资源的自动回收技术.
局部资源的管理
在讨论Go语言解决方案之前, 我们先看看C++是怎么管理资源的.
C++中可以可以自动执行的代码主要是构造函数和析构函数. 因此, 很多资源的管理技术都是基于构造函数和析构函数实现.
比较常见的是C++的RAII(Resource Acquisition Is Initialization)技术, 即初始化中获取资源. 比如在多线程编程中用到的MutexLocker
:
这样在使用Mutex
的时候就不会忘记解锁的操作了:
其实RAII中最重要的是退出locker
作用域是自动执行对象的析构函数, 这里也就是mu_->Unlock();
语句.
C++的构造函数其实是次要的. 关于禁用C++构造函数的讨论可以参考我的 另一个文章: C++去掉构造函数会怎么样?
因为构造函数经常是通过显示定义变量而隐式调用的, 因此用普通的全局函数也 可以实现构造函数的功能(唯一的约束是值容器). 其实C语言的fopen
就是一个FILE
对象的构造函数.
而作为C语言简约哲学继承者的Go语言同样也没有对构造函数做特殊处理. 在Go语言中构造函数这是约定以New
开头的普通函数, 比如NewBuffer
.
Go语言/UNIX之父Ken Thompson
发明了defer
语句, 完美地 解决了析构函数的问题(defer
还有很多其他特性).
因此, 在释放局部资源时, 可以用defer
管理. 因为C++的RAII的构造 函数和析构函数耦合过于紧密, 对于资源申请失败的问题就比较麻烦. 但是Go语言的defer
则灵活很多.
比如, Go语言版本基于defer
的Mutex
用法
对于可能申请失败的资源也很好处理:
使用defer
语句, 可以方便地组合函数/闭包和资源对象. 即使panic
时, defer
也能保证资源的正确释放.
非局部资源的管理
我们之前看到的都是在局部使用和释放资源. 如果资源的生命周期很长, 而且可能被多个模块共享和随意传递的话, defer
语句就不好处理了.
解决的思路和C++的RAII的方式类似: 我们需要一个能够自己定义的类似 析构函数的技术.
但是因为Go语言有GC特性, 因此没有析构函数的概念. 不过runtime
包的 func SetFinalizer(x, f interface{})
函数可以提供类似的机制.
比如, 我们可以包装一个文件对象, 在没有人使用的时候能够自动关闭:
在使用runtime.SetFinalizer
时, 需要注意的地方是尽量要用指针访问 内部资源. 这样的话, 即使*MyFile
对象忘记释放, 或者是被别的对象无意中覆盖, 也可以保证内部的文件资源可以正确释放.
总结
Go语言是短小精悍的语言, 它的设计哲学来自UNIX和C语言的KISS原则. 但是Go语言的语法规范虽然很少(50+页), 但是却提供了无限可能的组合方式.
Go语言之父Rob Pike
有篇文章叫 少是指数级的多. 但是为什么少就是多呢?
参考下数学公理就明白了: 数学的基础规则是很简单的, 但是组合方式却是无穷的. Go语言的思路也是提供虽然少但却是正交的基础特性, 通过不同特性的无穷的 组合方式来应对各种问题(一个反例就是C++的构造函数和析构函数).
这里我们主要是基于Go语言的defer
和runtime.SetFinalizer
两个基础特性, 来解决资源的自动回收问题.
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [docker]Tomcat安装及配置访问权限
- Nginx+Keepalived 保障HA高可用
- Hash一致性闭环算法 - ( 适用于Redis扩容、Nginx多级缓存 等等 )
- MySQl 事务测试
- 百万数据,SQL数据分流查询
- Linux 安装Apr - 提高Tomcat 的可伸缩性和性能
- Linux下MySQL的彻底卸载
- Excel生成导入SQL语句,快速创建批量 insert/update/delete
- MySQL 执行计划详解
- MySQL 5.7详细安装步骤
- win10必备效率预览神器-Quick look
- 史上最全-Nginx和Tengine安装部署
- Jenkins+Ansible 实现自动化运维 DevOps
- FFmpeg 内容介绍 音视频解码和播放
- 开源:安卓手机app控制arduino,通过esp8266-01