关于Go的Channel,Silce,Map

1. Chan

1.1 channel 数据结构

type hchan struct {
	qcount   uint           // 队列中的全部元素个数
	dataqsiz uint           // 底层循环数组的长度
	buf      unsafe.Pointer 
	// 缓冲链表 buf 指向底层循环数组,只有缓冲型的 channel 才有。环型的缓存
	elemsize uint16 // chan中的元素大小
	closed   uint32 // chan是否被关闭的标识
	elemtype *_type // chan 中元素类型
	sendx    uint   // 已 发送元素 在循环数组中的索引
	recvx    uint   // 已 接受元素 在循环数组中的索引
	recvq    waitq  // 等待接收的 goroutine 队列
	sendq    waitq  // 等待发送的 goroutine 队列
	lock mutex // 保护所有元素
}

type waitq struct {
	first *sudog
	last  *sudog
}

在这里插入图片描述

我们可以看到chan其实是有锁的。所以是并发安全的。

1.2 读取已经关闭channel的有缓冲通道

  • 有缓冲的话,会先把通道中的值给读出来,之后就会变成读取的是零值。
ch := make(chan int,3)
for i:=0; i<3; i++ {
	ch <- i
}
close(ch)
for c := range ch {
	fmt.Println(c) // 0 1 2
}

1.3 如果有一个300缓冲的channel,在2核的服务器上,读写300个数据,如何设置线程数,并发数?

1.4 注意点

  • select 中的break无法跳出for循环
  • for + select closed channel 会死循环

2. Slice

2.1 Slice 和 Array的区别

  • Slice 是可变的,Array 是不可变的
  • Slice的底层就是用Array实现的

2.2 Append 原理

Append 就是如果slice不需要扩容,那么就先进行扩容,再进行append

func append(slice []Type,elems ...Type)  []Type		

这里传递参数是值拷贝因此append无法修操作原切片。值为结构体的情况下考虑使用指针。返回一个新的切片。

  • 错误
func main(){
	 var array []int
	 array = Append(array)
	 fmt.Println(array) // []
}

func Append(s []int){
	 s = append(s, 1)
}
  • 正确
func main(){
	 var array []int
	 array = Append(array)
	 fmt.Println(array) // [1]
}

func Append(s []int)[]int {
	 s = append(s, 1)
	 return s
}

例子:

func Append(s[]int) {
	//s[0] = 1024 	//① 位置1
	s = append(s,100)
	s = append(s,200)
	//s[0] = 1024   //② 位置2
	// fmt.Println(s) 
}

func main(){
	var s []int
	for i:=0; i<3; i++ {
		s = append(s,i)
	}
	Append(s)
	fmt.Println(s)
}

① 位置1:
我们在main函数中的输出结果是 [1024 1 2] 我们的append是值拷贝,是不会进行修改原切片

② 位置2:
main函数中输出结果:[0 1 2] 因为这里其实发生了扩容,那么已经是扩容了,那么扩容部分就是另一块内存了。所以就没有修改成功。

2.3 命名区别

1. var a []int
// 定义一个 []int 类型的变量 a , 并分配内存空间给 a 赋 []int 的 nil。
2. a := []int{}
// 定义一个 []int 类型的变量 a , 并分配内存空间给 a , 但是不为nil。
3. a := make([]int,3)
// 分配内存函数,仅用于 chan、map 和 slice,返回的数据类型就是这三个类型本身
// chan、map 和 slice 这三种类型本身就是引用类型,所以没必要返回指针类型
4. a := new(int) 
// 声明一个 int 型指针 a,分配一个 int 的内存空间,并把内存地址给 a。

3. map

推荐这篇博文 Map底层实现

3.1 底层结构

type hmap struct {
	// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
	// Make sure this stays in sync with the compiler's definition.
	count     int // 键值对的数量
	flags     uint8 
	// 状态标识,比如正在被写、buckets和oldbuckets在被遍历、等量扩容(Map扩容相关字段)
	B         uint8  // 2^B=len(buckets)
	noverflow uint16 // 溢出桶里bmap大致的数量
	hash0     uint32 // hash 因子
	buckets    unsafe.Pointer 
	// 指向一个数组(连续内存空间),数组的类型为[]bmap,这个字段我们可以称之为正常桶
	oldbuckets unsafe.Pointer 
	// 扩容时,存放之前的buckets(Map扩容相关字段)
	nevacuate  uintptr        
	// 分流次数,成倍扩容分流操作计数的字段(Map扩容相关字段)
	extra *mapextra 
	// 溢出桶结构,正常桶里面某个bmap存满了,会使用这里面的内存空间存放键值对
}

3.2 赋值

var mp1 map[int][int] // 1
mp1[1]=1
mp2 := map[int][int]{} // 2
mp2[1]=1

情况 1 :报错,var的赋值 mp1是为nil的。
情况 2 :可行,而第二种情况的赋值是不为nil的。

3.3 map 是线程安全的吗?

map的底层hmap是没有加锁的。所以并不是线程安全的。

3.4 map的扩容注意点

具体扩容涉及到的太多了,这里过多讲解。

以下写法是错误的,因为当map扩容的时候,他的扩容地址会发生变化,所以key value都是不可取地址。并且map删除key之后是不会自动缩容的。

m:=make(map[int][int])
m[1]=1
fmt.Println(&m[1])
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
给出相同功能的代码import os import numpy as np import nibabel as nib import imageio from PIL import Image def read_niifile(niifilepath): # 读取niifile文件 img = nib.load(niifilepath) # 提取niifile文件 img_fdata = img.get_fdata(dtype='float32') return img_fdata def save_fig(niifilepath, savepath, num, name): # 保存为图片 name = name.split('-')[1] filepath_seg = niifilepath + "segmentation\" + "segmentation-" + name filepath_vol = niifilepath + "volume\" + "volume-" + name savepath_seg = savepath + "segmentation\" savepath_vol = savepath + "volume\" if not os.path.exists(savepath_seg): os.makedirs(savepath_seg) if not os.path.exists(savepath_vol): os.makedirs(savepath_vol) fdata_vol = read_niifile(filepath_vol) fdata_seg = read_niifile(filepath_seg) (x, y, z) = fdata_seg.shape total = x * y for k in range(z): silce_seg = fdata_seg[:, :, k] if silce_seg.max() == 0: continue else: silce_seg = (silce_seg - silce_seg.min()) / (silce_seg.max() - silce_seg.min()) * 255 silce_seg = np.uint8(Image.fromarray(silce_seg).convert('L')) silce_seg = cv2.threshold(silce_seg, 1, 255, cv2.THRESH_BINARY)[1] if (np.sum(silce_seg == 255) / total) > 0.015: silce_vol = fdata_vol[:, :, k] silce_vol = (silce_vol - silce_vol.min()) / (silce_vol.max() - silce_vol.min()) * 255 silce_vol = np.uint8(Image.fromarray(silce_vol).convert('L')) imageio.imwrite(os.path.join(savepath_seg, '{}.png'.format(num)), silce_seg) imageio.imwrite(os.path.join(savepath_vol, '{}.png'.format(num)), silce_vol) num += 1 return num if name == 'main': path = r'C:\Users\Administrator\Desktop\LiTS2017' savepath = r'C:\Users\Administrator\Desktop\2D-LiTS2017' filenames = os.listdir(path + "segmentation") num = 0 for filename in filenames: num = save_fig(path, savepath, num, filename) 。用另一段代码实现相同功能
05-25
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小生凡一

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值