当前位置: 首页 > news >正文

公司网站建设调研背景浙江省人才网官方网站建设厅招聘

公司网站建设调研背景,浙江省人才网官方网站建设厅招聘,营销推广运营 网站,wordpress 数据库大小字符串 其实就是字符数组 注意 字节数组与字符串可以相互转换 a : hello world b : []byte(a) c : string(b)字节数组转换为字符串在运行时调用了slicebytetostring函数。需要注意的是#xff0c;字节数组与字符串的相互转换并不是简单的指针引用#xff0c;…字符串 其实就是字符数组 注意 字节数组与字符串可以相互转换 a : hello world b : []byte(a) c : string(b)字节数组转换为字符串在运行时调用了slicebytetostring函数。需要注意的是字节数组与字符串的相互转换并不是简单的指针引用而是涉及了复制。当字符串大于32字节时还需要申请堆内存因此在涉及一些密集的转换场景时需要评估这种转换带来的性能损耗 当字符串转换为字节数组时在运行时需要调用stringtoslicebyte函数其和slicebytetostring函数非常类似需要新的足够大小的内存空间。当字符串小于32字节时可以直接使用缓存buf。当字符串大于32字节时rawbyteslice函数需要向堆区申请足够的内存空间。最后使用copy函数完成内存复制。 切片 概要 有data、len 、cap 三个元素。 分别指向数据长度容量底层是一个数组 切片是一种简化版的动态数组。切片的在go中的定义为如下在对切片赋值就是修改指向数组的指针lencap的值。而在拷贝的时候如果直接使用则会复制被拷贝的切片的数组指针caplen值因此会指向同一个地址而使用copy的话会把被拷贝的切片中的数组的值复制到拷贝的切片的数组中。即地址是不同的 切片在被截取时的另一个特点是被截取后的数组仍然指向原始切片的底层数据。 要真正复制切片需要用copy slice: make(int[], 4, 6)Go语言中切片的复制其实也是值复制但这里的值复制指对于运行时SliceHeader结构的复制。如图底层指针仍然指向相同的底层数据的数组地址因此可以理解为数据进行了引用传递。切片的这一特性使得即便切片中有大量数据在复制时的成本也比较小这与数组有显著的不同 切片扩容 cap增长的策略 如果新申请容量cap大于2倍的旧容量old.cap则最终容量newcap是新申请的容量cap。如果当前大小小于1024则两倍增长否则每次增长25%直到满足期望。如果新申请容量cap大于2倍的旧容量old.cap则最终容量newcap是新申请的容量cap。 // slice 扩容伪代码 {newcap : old.capdoublecap : newcap newcapif cap doublecap {newcap cap} else {if old.len 1024 {newcap doublecap} else {for newcap cap {newcap newcap / 4}}}map 源码 // Map contains Type fields specific to maps. type Map struct {Key *Type // Key typeElem *Type // Val (elem) typeBucket *Type // internal struct type representing a hash bucketHmap *Type // internal struct type representing the Hmap (map header object)Hiter *Type // internal struct type representing hash iterator state }// A header for a Go map. type hmap struct {// 元素个数调用 len(map) 时直接返回此值count intflags uint8 // flags代表当前map的状态是否处于正在写入的状态等B uint8 // buckets 的对数 log_2// overflow 的 bucket 近似数 noverflow为map中溢出桶的数量。当溢出的桶太多时map会进行same-size map growth其实质是避免溢出桶过大导致内存泄露noverflow uint16// 计算 key 的哈希的时候会传入哈希函数hash0 uint32buckets unsafe.Pointer // 指向内存的指针可以看作是[]bmap。 其大小为 2^B. 如果元素个数为0就为 nil// 扩容的时候buckets 长度会是 oldbuckets 的两倍oldbuckets unsafe.Pointer// 指示扩容进度小于此地址的 buckets 迁移完成nevacuate uintptrextra *mapextra // optional fields }// buckets指向的结构体 type bmap struct {tophash [bucketCnt]uint8 // bucketCnt值固定为8个也就是每个bmap最大能存储8个key-value对。 }// go编译器在编译时会扩展bmap为如下的结构 type bmap struct {topbits [8]uint8keys [8]keytypevalues [8]valuetypepad uintptroverflow uintptr }type mapextra struct {// If both key and elem do not contain pointers and are inline, then we mark bucket// type as containing no pointers. This avoids scanning such maps.// However, bmap.overflow is a pointer. In order to keep overflow buckets// alive, we store pointers to all overflow buckets in hmap.extra.overflow and hmap.extra.oldoverflow.// overflow and oldoverflow are only used if key and elem do not contain pointers.// overflow contains overflow buckets for hmap.buckets.// oldoverflow contains overflow buckets for hmap.oldbuckets.// The indirection allows to store a pointer to the slice in hiter.overflow *[]*bmapoldoverflow *[]*bmap// nextOverflow holds a pointer to a free overflow bucket.nextOverflow *bmap } /* 当一个 map 的 key 和 elem 都不含指针并且他们的长度都没有超过 128 时(当 key 或 value 的长度超过 128 时, go 在 map 中会使用指针存储), 该 map 的 bucket 类型会被标注为不含有指针, 这样 gc 不会扫描该 map, 这会导致一个问题, bucket 的底层结构 bmap 中含有一个指向溢出桶的指针(uintptr类型, uintptr指针指向的内存不保证不会被 gc free 掉), 当 gc 不扫描该结构时, 该指针指向的内存会被 gc free 掉, 因此在 hmap 结构中增加了 mapextra 字段, 其中 overflow 是一个指向保存了所有 hmap.buckets 的溢出桶地址的 slice 的指针, 相对应的 oldoverflow 是指向保存了所有 hmap.oldbuckets 的溢出桶地址的 slice 的指针, 只有当 map 的 key 和 elem 都不含指针时这两个字段才有效, 因为这两个字段设置的目的就是避免当 map 被 gc 跳过扫描带来的引用内存被 free 的问题, 当 map 的 key 和 elem 含有指针时, gc 会扫描 map, 从而也会获知 bmap 中指针指向的内存是被引用的, 因此不会释放对应的内存。 */ 溢出桶 Go语言选择将key与value分开存储而不是以key/value/key/value的形式存储是为了在字节对齐时压缩空间 hmap 结构相当于 go map 的头, 它存储了哈希桶的内存地址, 哈希桶之间在内存中紧密连续存储, 彼此之间没有额外的 gap, 每个哈希桶最多存放 8 个 k/v 对, 冲突次数超过 8 时会存放到溢出桶中, 哈希桶可以跟随多个溢出桶, 呈现一种链式结构, 当 HashTable 的装载因子超过阈值(6.5) 后会触发哈希的扩容 冲突检测 Go语言中的哈希表采用的是开放寻址法中的线性探测Linear Probing策略线性探测策略是顺序每次探测间隔为1的 插入过程 例如m1 map[string]string插入一条数据的过程如下 insert “key1 name”:“乔布斯”hashvalue hash(“key1 name”)slot hashvalue的低8bit % len(m1)例如m1的槽位是4个则slot hashvalue % 4。假设slot 2 hashvalue的高8bit这条数据应该插入到bmap中的第几个子槽。如果bmap已经写满8个则读取overflow指向的下一个紧邻着的bmap(溢出桶)去插入这条数据 删除过程 其核心代码位于runtime.mapdelete函数中删除操作同样需要根据key计算出hash的前8位和指定的桶同样会一直寻找是否有相同的key如果找不到则会一直查找当前桶的溢出桶直到到达溢出桶链表末尾。如果查找到了指定的key则会清空该数据将hash位设置为emptyOne。如果发现后面没有元素则会将hash位设置为emptyRest并循环向上检查前一个元素是否为空 扩容 当插入的元素越来越多导致哈希桶慢慢填满导致溢出桶越来越多所以发生哈希碰撞的频率越来越高就需要进行扩容 若装载因子过大, 说明此时 map 中元素数目过多, 此时 go map 的扩容策略为将 hmap 中的 B 增一, 即将整个哈希桶数目扩充为原来的两倍大小, 而当因为溢出桶数目过多导致扩容时, 因此时装载因子并没有超过 6.5, 这意味着 map 中的元素数目并不是很多, 因此这时的扩容策略是等量扩容, 即新建完全等量的哈希桶, 然后将原哈希桶的所有元素搬迁到新的哈希桶中。 需要注意的几点 3.1 Go map遍历为什么是无序的 使用 range 多次遍历 map 时输出的 key 和 value 的顺序可能不同。这是 Go 语言的设计者们有意为之旨在提示开发者们Go 底层实现并不保证 map 遍历顺序稳定不要依赖 range 遍历结果顺序。 主要原因有2点 map在遍历时并不是从固定的0号bucket开始遍历的每次遍历都会从一个随机值序号的bucket再从其中随机的cell开始遍历map遍历时是按序遍历bucket同时按需遍历bucket中和其overflow bucket中的cell。但是map在扩容后会发生key的搬迁这造成原来落在一个bucket中的key搬迁后有可能会落到其他bucket中了从这个角度看遍历map的结果就不可能是按照原来的顺序了。 因此如果不加入随机数在不发生扩容情况下一些不熟悉该原理的开发者会认为map是有序的一旦依赖这个特性就会引发bug。所以golang直接通过加随机数在初始化迭代器时会生成一个随机数决定从哪一个bucket开始迭代避免问题的发生。这就是map为什么每次遍历顺序是不一样的原因。 3.2 如何让map有序 把key取出来进行排序再通过key依次从map中取值。 3.3 map并发读写会产生什么情况 map在默认情况下时不支持并发的这是由于golang的设计者考虑到使用map的场景都不是并发访问如果map并发读写会产生什么呢如果并发时写入则会产生panic。runtime.map 代码判断 //赋值时检查是否在写入 func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {if h.flagshashWriting ! 0 {throw(concurrent map writes)} } //读取数据时检查是否在写入 func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {if h.flagshashWriting ! 0 {throw(concurrent map read and map write)}}3.4 如何安全使用map Go map不是线程安全的在使用过程中如果需要保证线程安全则需要保持同步。 使用sync.Mutex或sync.RWMutex进行加锁使用go官方提供的sync.Map替代map 3.5 map中的key可以取地址吗 不可以因为key对应的value的内存地址可能因为扩容而变化所以不允许取地址。也正因为如此下面代码是错误的。 type Student struct {name string } func main() { m : map[string]Student{people: {zhoujielun}} m[people].name wuyanzu }函数 闭包 一个函数捕获了和他在同一个作用域的其他常量和变量.这就意味着当闭包被调用的时候,不管在程序什么地方调用,闭包能够使用这些常量或者变量. 它不关心这些捕获了的变量和常量是否已经超出了作用域,所以只有闭包还在使用他,这些变量就还会存在 在go里面,所有的匿名函数都是闭包 闭包是一个函数值它引用了函数体之外的变量。 这个函数可以对这个引用的变量进行访问和赋值换句话说这个函数被“绑定”在这个变量上 例如函数 adder 返回一个闭包。每个返回的闭包都被绑定到其各自的 sum 变量上。 package mainimport fmtfunc adder() func(int) int {sum : 0return func(x int) int {sum xreturn sum} }func main() {pos, neg : adder(), adder()for i : 0; i 10; i {fmt.Println(pos(i),neg(-2*i),)} }
http://www.zqtcl.cn/news/364051/

相关文章:

  • 网站域名没有实名认证微信平台开发技术
  • 自己用电脑做虚拟机怎么建网站个人网站 icp 代理
  • 嘉兴网站建设999 999中国建设招标网是私人网站吗
  • 网站程序设置主页面零基础学wordpress pdf下载
  • 网站代码优化有哪些专做立体化的网站
  • 单县网站定制培训机构专业
  • 网站防红链接怎么做网站建设中提示页面
  • 网站开发和游戏开发的区别互联网服务平台投诉
  • 杭州定制网站公司出名的设计网站
  • 网站查询访问注册电气工程师考试
  • 北京企业网站推广哪家公司好电商平台代运营
  • 北京快速建站模板信息管理系统网站开发
  • 做网站后台需要写代码吗做网站收多少钱
  • 企业手机网站建设咨询为企业设计一个网站
  • 做网站平台成本珠海自适应网站设计
  • 做网站手机端需要pc端的源代码吗经营网站需要注意什么
  • 域名购买之后怎么做网站做+淘宝客最大的网站是叫什么
  • 在线营销型网站wordpress 怎么添加即时联系窗口
  • 网站加图标网站开发属于无形资产
  • 个人网站开发与设计摘要企业营销策划心得体会
  • 专注苏州网站优化自建网站的优缺点
  • 网络建站怎么做js与asp.net做的网站
  • 个人网站设计理念自己做简历网站
  • 做网页设计的网站网站流量多少做网盟
  • 上海协会网站建设网站制作培训费用
  • 学会网站建设总结淮北市建市
  • 泉州开发网站的公司有哪些域名不用了需要注销吗
  • 重庆网站推广平台东莞整站优化火速公司
  • 商务网站建设综合实训网站推广效果怎么样
  • 成都品牌网站建设电话项目外包平台接活