ring buffer(二)

在并发编程中,Data Race(数据竞争) 是一个常见的问题。当多个 goroutine 同时访问共享资源(如变量、数据结构等),并且至少有一个 goroutine 对资源进行写操作时,就可能发生 Data Race。Data Race 会导致程序行为不可预测,甚至引发崩溃。

在上一篇文章中,我们实现了一个简单的环形缓冲区。然而,这个实现并没有考虑并发访问的情况,因此在多 goroutine 环境下可能会出现 Data Race。本文将介绍如何通过 Golang 的同步机制(如 sync.Mutexsync.RWMutex)来避免环形缓冲区中的 Data Race。


为什么需要避免 Data Race?

在环形缓冲区的实现中,headtailisFull 是共享资源。如果多个 goroutine 同时读写这些资源,可能会导致以下问题:

  1. 数据不一致:例如,一个 goroutine 正在写入数据,而另一个 goroutine 同时读取数据,可能会导致读取到错误的值。
  2. 缓冲区状态错误:例如,isFull 的状态可能被错误地更新,导致缓冲区无法正确判断是否已满或为空。

为了避免这些问题,我们需要使用同步机制来保护共享资源。

Read More

Comments

ring buffer(一)

在软件开发中,环形缓冲区(Ring Buffer) 是一种非常常见的数据结构,尤其在需要高效处理数据流的场景中,如音频处理、网络数据包处理、日志系统等。环形缓冲区的主要特点是固定大小,当缓冲区满时,新的数据会覆盖旧的数据,形成一个“环形”的结构。

本文将介绍环形缓冲区的基本概念,并使用 Golang 实现一个简单的环形缓冲区。

什么是环形缓冲区?

环形缓冲区是一种线性数据结构,但它通过逻辑上的循环使用内存空间,使得当缓冲区满时,新的数据可以覆盖旧的数据。它的主要优点包括:

  1. 高效的内存使用:由于缓冲区大小固定,内存分配一次后不再需要动态调整。
  2. 高效的插入和删除操作:由于数据是顺序存储的,插入和删除操作的时间复杂度为 O(1)。
  3. 适用于流式数据处理:环形缓冲区非常适合处理连续的数据流,如音频、视频、网络数据包等。

Read More

Comments

RSA算法

RSA算法

RSA算法是一种非对称加密算法,有一对秘钥,公钥加密,私钥解密

关于秘钥长度,最常见的有1024bit,秘钥越长越安全,但是对应的需要加密时间也会变长,这个自己做取舍,一般1024bit已经很安全了。

加密的内容跟秘钥的长度也有关系,一次能加密的内容等于秘钥的长度,所以对于1024bit长度的秘钥,每次能加密(1024/8)=128byte的内容,超过128bit的内容就需要分段加密了。

Comments

关于Django执行原生SQL查询参数问题

开端

最近跟同事吃饭时,同事说遇到一个奇怪的问题,在使用Django执行原生查询的时候得到了意想不到的结果,排查两小时无果,听起来比较好奇,就想探究下,下面记录下探索过程。

问题描述

很简单的一个sql类似这样

1
2
3
4
5
6
7
8
9
10
11
// SELECT * FROM myapp_person WHERE id in (...)

// 1. 转换成Django查询语法可以这么写
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE id in (%s)'% ('1,2,3'))
>>> print(qs.query)
SELECT * FROM myapp_person WHERE id in (1,2,3)

// 2. 按照django文档也可以使用params参数
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE id in (%s)', ['1,2,3'])
>>> print(qs.query)
SELECT * FROM myapp_person WHERE id in (1,2,3)

Read More

Comments

基于位操作的角色权限设计

在软件开发中,权限管理是一个常见的需求。无论是Web应用、桌面应用还是移动应用,都需要对用户的权限进行精细化管理,以确保系统的安全性和功能的合理分配。传统的权限管理方法通常使用角色和权限的关联表,但这种方法在权限数量较多时可能会变得复杂且低效。本文将介绍一种基于位操作的角色权限设计方法,通过位运算实现高效、灵活的权限管理。

1. 位操作简介

位操作是计算机科学中的一种基本操作,它直接对二进制位进行操作。常见的位操作包括:

  • 与运算(AND)&,两个位都为1时结果为1,否则为0。
  • 或运算(OR)|,两个位中至少有一个为1时结果为1,否则为0。
  • 异或运算(XOR)^,两个位不同时结果为1,否则为0。
  • 取反运算(NOT)~,将每一位取反,0变1,1变0。
  • 左移(<<):将二进制位向左移动,右侧补0。
  • 右移(>>):将二进制位向右移动,左侧补0或补1(取决于符号位)。

位操作的高效性使其在权限管理中具有很大的优势。

2. 基于位操作的权限设计

2.1 权限定义

在基于位操作的权限设计中,每个权限用一个二进制位表示。例如,假设我们有四个权限:

  • 权限A:0001(二进制)
  • 权限B:0010(二进制)
  • 权限C:0100(二进制)
  • 权限D:1000(二进制)

每个权限对应一个唯一的二进制位,这样我们可以通过一个整数的二进制表示来存储多个权限。

Read More

Comments

129. 求根到叶子节点数字之和

leetcode每日一题疑惑

今天的leetcode每日一题129. 求根到叶子节点数字之和

看完题以后想了种解法(比较繁琐,层序遍历,记录到根节点的所有数字,最后再求和),不要在意细节,看完题解发现自己写的太复杂了,此文不讨论算法,记录下其中的一个疑惑,希望有大佬给解答下。

先上代码

Read More

Comments

惊喜的一天

2020年10月26日,星期一,本是平凡的一天,枯燥的周一,没想到晚上来了点惊喜,十四五年没见的同学突然联系上了。

初中在离家挺远的安国上学,认识了好多朋友,但是初中毕业以后就回家上学了,好多人慢慢失去了联系,晚上几个常在安国本地的同学聚在一起,想起了我,其中一人留有我的联系方式,还是上大学加上的,给我开了视频,让我一个一个说名字,说实话,好多年了,名字突然叫不上来,但是看着面容都能认出来,还有原来的影子,最大的特点就是全部变胖了。

有太多的话题,激动的说不出话来,有点想哭的感觉,当时大家在一起玩的很好,关系都不错,只是没有联系了,再联系还是感觉很亲切,大家都喝多了,跟他们视频完脑海中一直浮现十四五年前的画面。

初中离家远,老师同学都很照顾我,很感激!

最后约定找时间一定见面好好叙叙旧,太想念大家了,初中的友谊真的深,大部分关系都很好,越往后年龄越大,交心的朋友越来越少了,尤其工作以后,在北京这个快节奏的城市中,大家忙忙碌碌,没有了生活,这一瞬间让人忘记了生活的烦恼,全是对过去美好的回忆,真的很好,无法入眠的一夜。

Comments

Go中var、new、make介绍

go中声明变量有很多方式,五花八门(乱七八糟),实际上写多了会固化几种写法,比如全局变量会在外面用var声明,方法内变量一般都是 x := xxx 这样,至于channel、slice、map都会使用make关键字,而new实际当中用的很少

var

使用var关键字声明变量,系统会默认为变量分配内存空间,并赋值该类型的0值

1
2
var i int 
fmt.Println(i) // 0

如果声明指针类型的变量,就不会分配内存空间,默认是nil

1
2
var i *int
fmt.Println(i == nil) // true

此时需要配合new关键字使用,i指向一块内存空间

1
2
3
i = new(int)
fmt.Println(i) // 0xc000018030
fmt.Println(*i) // 0

new和make的区别

new 和 make 都会分配内存,new返回指向该类型内存地址的指针,并赋值该类型的0值,make只能用于channel、slice、map,返回的是引用类型,并初始化该类型

项目中使用较多的是slice,如果我们能明确知道slice的长度,声明的时候直接指定,能够避免reslice扩容造成的元素搬迁(追求性能,不过也是一个好习惯)

s := make([]int, 0, 10)

如果不能明确知道,一般这么定义

s := make([]int, 0)

今天发现一段代码这么定义直接使用的

var s []int

在实际项目中一直习惯于用make关键字来初始化slice,很少用关键字var,这种定义的slice为nil,比较好奇为啥没有出错,查看发现后面用了append操作,append操作可以接收nil的切片,在内部会使用mallocgc进行内存分配,所以这么写是可以的,觉得容易记混的话,还是都使用make来进行初始化,就会避免出现不必要的bug

Comments

leetcode -- 前缀树

leetcode上的一道设计题,要求实现trie这种数据结构,包含插入、查找、前缀查找的操作
https://leetcode-cn.com/problems/implement-trie-prefix-tree/

首先定义Trie struct

1
2
3
4
5
type Trie struct {
children []*Trie
isWord bool //是否为单词
part byte
}

Read More

Comments

groupcache 源码系列(一)一致性hash算法

Hash

1
2
// Hash 在此代码中代表函数类型,返回的是无符号32位整数
type Hash func(data []byte) uint32

Read More

Comments