编程语言

  • go logo
    Go,  技术,  编程语言

    golang 指针参数传递与赋值

    golang指针参数传递,实际也是值拷贝,传递的是指针所指向的内存地址。 所以,在函数内部的修改,实际是对该内存地址的修改,所以会生效。 但若在函数内部,给该指针参数重新分配一块新的内存地址,然后再对其修改,那么修改 对于函数外部而言就不会再生效了。 传递nil, 函数内初始化 函数内重新初始化 不重新赋值,只修改 综上所述,开发过程中一定要牢记 ,对于指针参数的重新赋值一定要慎重。

  • go logo
    Go,  技术,  编程语言

    从零开始搭建go项目(gin框架)(六) – 接口实现

    本节内容,我们正式实现一个添加用户的接口,实现我们整个项目接口请求的层级。 接口代码层级 在根目录下,新创建 ./repositories 和 ./models 目录,接口请求的数据逻辑顺序如下: route -> api -> services -> repositories -> models 接口实现 创建 ./models/user.go: 创建 ./repositories/user.go: 创建./services/user.go: 增加路由,修改 ./router/router.go 接口测试 至此,一个添加用户的接口就实现了 ~

  • php logo
    PHP,  技术,  编程语言

    php 去除文件Bom头

    遇到文件处理,特别是excel文件处理时,经常会遇到bom头的问题,下面我们介绍下如何去除文件的Bom头。 代码 原理 实际应用的是sed命令: 这种方式,不需要将文件内容加载到内存里面,减少了内存的消耗以及大文件可能造成的内存超限问题。

  • go logo
    Go,  技术,  编程语言

    从零开始搭建go项目(gin框架)(五) – 支持Mysql

    本节内容,我们将mysql引入我们的框架 (本地mysql部署可参考 Mysql集群部署(主从复制)。 第一步 引入mysql相关服务 第二步 创建测试库表 第三部 对mysql进行封装 创建./library/database/mysql.go : 第四步 增加mysql配置与读取 ./conf/config.yaml, 新增 ./conf/config.go: 第五步 mysql初始化 创建文件./helpers/mysql.go: 第六步 main函数中调用 ./main.go : 至此,我们项目就已经支持mysql使用啦~,下一章我们再介绍mysql在项目中的具体使用 参考链接 https://gorm.io/

  • go logo
    Go,  技术,  编程语言

    Map详解 – golang

    基础 哈希表 哈希表(散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做哈希(散列)函数,存放记录的数组叫做哈希(散列)表。 golang中的map是基于哈希表(也被称为散列表)实现的,所以,要进一步理解map的实现,就需要对哈希表有一定的了解。 学习哈希表首先要理解两个概念:哈希函数和哈希冲突 哈希函数 哈希函数(常被称为散列函数)是可以用于将任意大小的数据映射到固定大小值的函数,常见的包括MD5、SHA系列等。 一个设计优秀的哈希函数应该包含以下特性: 均匀性:一个好的哈希函数应该在其输出范围内尽可能均匀地映射,也就是说,应以大致相同的概率生成输出范围内的每个哈希值。 效率高:哈希效率要高,即使很长的输入参数也能快速计算出哈希值。 可确定性:哈希过程必须是确定性的,这意味着对于给定的输入值,它必须始终生成相同的哈希值。 雪崩效应:微小的输入值变化也会让输出值发生巨大的变化。 不可逆:从哈希函数的输出值不可反向推导出原始的数据。 哈希冲突 哈希函数是将任意大小的数据映射到固定大小值的函数,但即使哈希函数设计得足够优秀,几乎每个输入值都能映射为不同的哈希值,当输入数据足够大,大到能超过固定大小值的组合能表达的最大数量数,冲突将不可避免! 如何解决哈希冲突 比较常用的Has冲突解决方案有链地址法和开放寻址法。 在讲链地址法之前,先说明两个概念: 哈希桶。哈希桶(也称为槽,类似于抽屉原理中的一个抽屉)可以先简单理解为一个哈希值,所有的哈希值组成了哈希空间。 装载因子。装载因子是表示哈希表中元素的填满程度。它的计算公式:装载因子=填入哈希表中的元素个数/哈希表的长度。装载因子越大,填入的元素越多,空间利用率就越高,但发生哈希冲突的几率就变大。反之,装载因子越小,填入的元素越少,冲突发生的几率减小,但空间浪费也会变得更多,而且还会提高扩容操作的次数。装载因子也是决定哈希表是否进行扩容的关键指标。 链地址法 将所有哈希地址相同的都链接在同一个链表中 ,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。例如有一组关键字为{19,14,23,01,68,20,84,27,55,11,10,79},其哈希函数为:H(key)=key MOD 13,使用链地址法所构建的哈希表如下图 所示: 开放寻址法 对于链地址法而言,槽位数m与键的数目n是没有直接关系的。但是对于开放寻址法而言,所有的元素都是存储在Hash表当中的,所以无论任何时候都要保证哈希表的槽位数m大于或等于键的数据n(必要时,需要对哈希表进行动态扩容)。 例如,在长度为 11 的哈希表中已填写好 17、60…

  • go logo
    Go,  技术,  编程语言

    golang并发控制

    golang对于并发的支持可以说是最好的,也是我们之所以采用go语言进行编程的一个重要的因素。 golang的并发控制,主要有以下几种方式: Channel 优点是实现简单,缺点是当需要大量创建协程时就需要有相同数量的channel,而且对于子协程继续派生出来的协程不方便控制。 WaitGroup WaitGroup是Golang应用开发过程中经常使用的并发控制技术。WaitGroup,可理解为Wait-Goroutine-Group,即等待一组goroutine结束。比如某个goroutine需要等待其他几个goroutine全部完成,那么使用WaitGroup可以轻松实现。 Add()操作必须早于Wait(), 否则会panic Add()设置的值必须与实际等待的goroutine个数一致,否则会panic

  • go logo
    Go,  技术,  编程语言

    golang 并发 append

    go中,切片可以算是我们最常用的结构之一,但是如果不注意的话,在并发情况下,对同一个切片进行append,极有可能会造成线程不安全的情况。 非线程安全现象 如,以下例子: 以上代码,不同次运行时,输出以下这类不符合预期的结果: 这就是因为线程不安全导致的 (实际业务中,可以通过 go run -race main.go 进行检测程序的安全性) 原因分析 slice的数据结构: 使用append向Slice追加元素时,如果Slice空间不足,将会触发Slice扩容,扩容实际上重新一配一块更大的内存,将原Slice数据拷贝进新Slice,然后返回新Slice,扩容后再将数据追加进去。 在并发情况下,如果该slice始终空间不足,那么其是线程安全的,因为每次append实际都是新生成的内存,不存在抢占的情况。但是,当slice空间充足,也即是cap>len, 有剩余的空间时,比如说,下一个空闲内存是a, 那么并发情况下,就会出现多个线程抢占往a中写数据的情况。 slice扩容遵从以下原则: 如果原Slice容量小于1024,则新Slice容量将扩大为原来的2倍; 如果原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍; 所以,根据以上的原则,在程序运行后,是很容易就会出现有空闲空间的情况,也就会造成线程不安全的产生。 解决办法 针对内存占用,我们最直接简单的办法就是给内存加锁,如下: 运行结果: 通过内存加锁,确保,同一时刻,只有一个线程对该块内存进行append操作,这就从根源上避免了抢占的问题。

  • go logo
    Go,  技术,  编程语言

    golang内存分配管理

    基础 为了方便自主的管理内存,golang的做法是,先向系统申请一块大的内存,然后将其分割成一个个小块,通过自己的内存分配算法来进行管理。 预申请的内存划分为spans、bitmap、arena三部分。其中arena即为所谓的堆区,应用中需要的内存从这里分配。其中spans和bitmap是为了管理arena区而存在的。 arena的大小为512G,为了方便管理把arena区域划分成一个个的page,每个page为8KB,一共有512GB/8KB个页; spans区域存放span的指针,每个指针对应一个page,所以span区域的大小为(512GB/8KB)*指针大小8byte = 512M; bitmap区域大小也是通过arena计算出来,不过主要用于GC。 mheap 系统通过mheap来管理预申请的内存. mheap内存管理示意图如下: central central是全局资源,为多个线程服务,当某个线程内存不足时会向central申请,当某个线程释放内存时又会回收进central。 cache cache作为线程的私有资源为单个线程服务。 mcache和span的对应关系如下图所示: span span是内存管理的基本单位,每个span用于管理特定的class对象, 跟据对象大小,span将一个或多个页拆分成多个块进行管理。 内存分配图解