Java程序员学习Go指南(终)
我的博客:https://www.luozhiyun.com/archives/215
context.Context类型
Context类型可以提供一类代表上下文的值。此类值是并发安全的,也就是说它可以被传播给多个 goroutine。
Context类型的值(以下简称Context值)是可以繁衍的,这意味着我们可以通过一个Context值产生出任意个子值。这些子值可以携带其父值的属性和数据,也可以响应我们通过其父值传达的信号。
context包中还包含了四个用于繁衍Context值的函数,即:WithCancel、WithDeadline、WithTimeout和WithValue。
所有的Context值共同构成了一颗代表了上下文全貌的树形结构。通过调用context.Background函数就可以得到上下文根节点,然后通过根节点可以产生子节点。如下:
rootNode := context.Background()
node1, cancelFunc1 := context.WithCancel(rootNode)
在上面的例子中,初始化了一个撤销节点,这个节点是可以给它所有子节点发送撤销信号的,如下:
cxt, cancelFunc := context.WithCancel(context.Background())
//发送撤销信号
cancelFunc()
//接受撤销信号
<-cxt.Done()
在撤销函数被调用之后,对应的Context值会先关闭它内部的接收通道,也就是它的Done方法会返回的那个通道。
然后,它会向它的所有子值(或者说子节点)传达撤销信号。这些子值会如法炮制,把撤销信号继续传播下去。最后,这个Context值会断开它与其父值之间的关联。
WithValue携带数据
WithValue函数在产生新的Context值(以下简称含数据的Context值)的时候需要三个参数,即:父值、键和值。
在我们调用含数据的Context值的Value方法时,它会先判断给定的键,是否与当前值中存储的键相等,如果相等就把该值中存储的值直接返回,否则就到其父值中继续查找。
如:
node2 := context.WithValue(node1, 20, values[0])
node3 := context.WithValue(node2, 30, values[1])
fmt.Printf("The value of the key %v found in the node3: %v\n",
keys[0], node3.Value(keys[0]))
fmt.Printf("The value of the key %v found in the node3: %v\n",
keys[1], node3.Value(keys[1]))
fmt.Printf("The value of the key %v found in the node3: %v\n",
keys[2], node3.Value(keys[2]))
fmt.Println()
最后,提醒一下,Context接口并没有提供改变数据的方法。
对象池sync.Pool
sync.Pool类型只有两个方法——Put和Get。Put 用于在当前的池中存放临时对象,它接受一个interface{}类型的参数;Get方法可能会从当前的池中删除掉任何一个值,然后把这个值作为结果返回。如果没有那么会使用当前池的New字段创建一个新值,并直接将其返回。
如下:
var ppFree = sync.Pool{
New: func() interface{} { return new(pp) },
}
Go 语言运行时系统中的垃圾回收器,所以在每次开始执行之前,都会对所有已创建的临时对象池中的值进行全面地清除。
临时对象池数据结构
在临时对象池中,有一个多层的数据结构。这个数据结构的顶层,我们可以称之为本地池列表。
在本地池列表中的每个本地池都包含了三个字段(或者说组件),它们是:存储私有临时对象的字段private、代表了共享临时对象列表的字段shared,以及一个sync.Mutex类型的嵌入字段。
临时对象池的Put方法总会先试图把新的临时对象,存储到对应的本地池的private字段中,只有当这个private字段已经存有某个值时,该方法才会去访问本地池的shared字段。
Put方法会在互斥锁的保护下,把新的临时对象追加到共享临时对象列表的末尾。
临时对象池的Get方法,总会先试图从对应的本地池的private字段处获取一个临时对象。只有当这个private字段的值为nil时,它才会去访问本地池的shared字段。
Get方法也会在互斥锁的保护下,试图把该共享临时对象列表中的最后一个元素值取出并作为结果。
并发安全字典sync.Map
键的实际类型不能是函数类型、字典类型和切片类型。由于这些键值的实际类型只有在程序运行期间才能够确定,所以 Go 语言编译器是无法在编译期对它们进行检查的,不正确的键值实际类型肯定会引发 panic。
也是因为Go没有类似java的泛型,所以我们通常要自己做类型限制,如下:
type IntStrMap struct {
m sync.Map
}
func (iMap *IntStrMap) Delete(key int) {
iMap.m.Delete(key)
}
func (iMap *IntStrMap) Load(key int) (value string, ok bool) {
v, ok := iMap.m.Load(key)
if v != nil {
value = v.(string)
}
return
}
func (iMap *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) {
a, loaded := iMap.m.LoadOrStore(key, value)
actual = a.(string)
return
}
func (iMap *IntStrMap) Range(f func(key int, value string) bool) {
f1 := func(key, value interface{}) bool {
return f(key.(int), value.(string))
}
iMap.m.Range(f1)
}
func (iMap *IntStrMap) Store(key int, value string) {
iMap.m.Store(key, value)
}
在IntStrMap类型的方法签名中,明确了键的类型为int,且值的类型为string。这些方法在接受键和值的时候,就不用再做类型检查了。
或者可以用反射来做类型校验,如下:
type ConcurrentMap struct {
m sync.Map
keyType reflect.Type
valueType reflect.Type
}
func NewConcurrentMap(keyType, valueType reflect.Type) (*ConcurrentMap, error) {
if keyType == nil {
return nil, errors.New("nil key type")
}
if !keyType.Comparable() {
return nil, fmt.Errorf("incomparable key type: %s", keyType)
}
if valueType == nil {
return nil, errors.New("nil value type")
}
cMap := &ConcurrentMap{
keyType: keyType,
valueType: valueType,
}
return cMap, nil
}
func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) {
if reflect.TypeOf(key) != cMap.keyType {
return
}
return cMap.m.Load(key)
}
func (cMap *ConcurrentMap) Store(key, value interface{}) {
if reflect.TypeOf(key) != cMap.keyType {
panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key)))
}
if reflect.TypeOf(value) != cMap.valueType {
panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value)))
}
cMap.m.Store(key, value)
}
Java程序员学习Go指南(终)的更多相关文章
- Java程序员学习Go指南(二)
摘抄:https://www.luozhiyun.com/archives/211 Go中的结构体 构建结构体 如下: type AnimalCategory struct { kingdom str ...
- Java程序员学习Go指南(三)
转载:https://www.luozhiyun.com/archives/213 人是否会进步以及进步得有多快,依赖的恰恰就是对自我的否定,这包括否定的深刻与否,以及否定自我的频率如何.这其实就是& ...
- Java程序员学习之路
1. Java语言基础 谈到Java语 言基础学习的书籍,大家肯定会推荐Bruce Eckel的<Thinking in Java>.它是一本写的相当深刻的技术书籍,Java语言基础部分基 ...
- 聊聊阿里社招面试,谈谈“野生”Java程序员学习的道路
引言 很尴尬的是,这个类型的文章其实之前笔者就写过,原文章里,笔者自称LZ(也就是楼主,有人说是老子的简写,笔者只想说,这位同学你站出来,保证不打死你,-_-),原文章名称叫做<回答阿里社招面试 ...
- 【Python】Java程序员学习Python(五)— 函数的定义和使用
不想做一个待宰的羔羊!!!!要自己变得强大.... 函数的定义和使用放在最前边还是有原因的,现在语言趋于通用,基本类型基本都是那些,重点还是学习对象的使用方法,而最根本的还是方法的使用,因此优先介绍, ...
- 【Python】Java程序员学习Python(二)— 开发环境搭建
巧妇难为无米之炊,我最爱的还是鸡蛋羹,因为我和鸡蛋羹有段不能说的秘密. 不管学啥,都要有环境,对于程序员来说搭建个开发环境应该不是什么难题.按顺序一步步来就可以,我也只是记录我的安装过程,你也可以滴. ...
- 如何准备阿里社招面试,顺谈 Java 程序员学习中各阶段的建议
引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...
- 写给自己的Java程序员学习路线图
恩,做开发的工作已经三年多了,说起来实在是惭愧,自己的知识树还像一棵小草一样,工作中使用到了许多的知识和技术,不过系统性不够.根基不牢.并且不够深入!当然,慢慢的我也更加的清楚,我需要学习一些什么样的 ...
- 写给自己的Java程序员学习路线图_转载
如下是我做开发这三年经常使用一些技术和工具,当然这些技术也都是需要加强的(有些是我一直使用的,不过不深入,有些内部的原理等等不是很清楚) 前端部分: 1)HTML:网页的核心语言,构成网页的基础 2) ...
随机推荐
- 根据经纬度查询附近几公里的门店(<5)代表5公里
select * from 表名 where status=1 and isopen =0 and jingyingtype=1 and waimai=1 and bstatus = 1 and (a ...
- 查看HBase表在HDFS中的文件结构(转发)
转自:http://greatwqs.iteye.com/blog/1839232
- 缓存, 队列(Redis,RabbitMQ)
Redis Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...
- MindManager使用技巧
任务窗格在右下角. 1.条件的设置与编辑 2.优先级视图 不是优先级图标 3.圆圈图 4.洋葱图的使用 右键选择背景再选择解锁所有背景就可以对所有圆形进行调整了 点图形边缘出现十字架可以进行移动 5 ...
- 010 Ceph RGW对象存储
一.对象存储 1.1 介绍 通过对象存储,将数据存储为对象,每个对象除了包含数据,还包含数据自身的元数据 对象通过Object ID来检索,无法通过普通文件系统操作来直接访问对象,只能通过API来访问 ...
- 解决echarts中的点击事件点击后走多次接口
使用echarts图点击图之后,走了很多次接口,后来发现添加一个off事件就可以解决了,具体如下:
- 【题解】Music Festival(树状数组优化dp)
[题解]Music Festival(树状数组优化dp) Gym - 101908F 题意:有\(n\)种节目,每种节目有起始时间和结束时间和权值.同一时刻只能看一个节目(边界不算),在所有种类都看过 ...
- 洛谷$P$2472 蜥蜴 $[SCOI2007]$ 网络流
正解:网络流 解题报告: 传送门! $umm$一看就是个最大流呗,,,就直接考虑怎么建图趴$QwQ$ 首先看到这个高度减小其实就相当于对这个点的次数有约束,就显然拆点呗,流量为高度 然后$S$连向左侧 ...
- python版飞机大战代码简易版
# -*- coding:utf-8 -*- import pygame import sys from pygame.locals import * from pygame.font import ...
- Spring中Bean的实例化与DI的过程
引言 前文我们介绍了关于如何学习Spring的源码以及解析了spring中加载配置文件注册Beandefinition的过程.今天我们继续学习DI的过程. 创建实例和DI过程 IOC和DI都是对spr ...