首页 > 编程知识 正文

golang 规则引擎,golang excel

时间:2023-05-05 16:36:27 阅读:172200 作者:4484

摘要锁定的成本很高,需要对基本数据类型进行上下文切换,并且可以在用户状态下使用原子操作执行线程安全操作,从而实现比独占锁定性能更高的sync/atomic程序包中的函数

求和(add )比较交换(compare and swap,简称CAS )加载(store )交换)原子操作函数需要的不是这个值本身,而是指向被操作值的指针

只要原子操作函数拿到了被操作值的指针只有这样,底层指令才能正确操作此内存地址上的数据。

的类型这些函数不针对太多的数据类型。 但是,对于这些类型中的每一种,

sync/atomic包支持一组函数。 这些数据类型为int32、int64、uint32、uint64、uintptr和unsafe软件包的Pointer。

但是,对于unsafe.Pointer类型,此软件包没有执行原子加法操作的函数。

减法atomic.AddInt32函数的第二个参数表示差分,其类型在int32中有符号。 如果你想做原子减法,把这个差分变成负整数就可以了。

atomic.AddInt64函数也是如此。 但是,要使用atomic.AddUint32和atomic.AddUint64函数进行原子减法运算,并不是那么容易的。 虽然没有符号,但也可以这样做,因为第二个参数的类型分别是uint32和uint64。 有点麻烦。

例如,在想对uint32型的被操作值18进行原子减法运算的情况下,例如如果差分是-3,则首先将该差分变换为有符号的int32型的值,接着将该值的类型变换为uint32,用公式记述的话是uint32(int32(-3 ) )

但是,请注意,以这种方式直接编写时,Go语言的编译器会报告错误。 “常数-3不在uint32类型的范围内”,即溢出表达式的结果值。

但是,您可以将int32(-3 )的结果值赋给变量delta,然后将delta的值转换为uint32类型的值,从而绕过编译器检查并获得正确的结果。

最后,通过将该结果作为atomic.AddUint32函数的第二个参数值,可以对uint32型的值进行原子减法运算。

还有更直接的方法。 可以根据以下表达式指定atomic.AddUint32函数的第二个参数值:

^uint32(-n-1 ) )其中n表示用负整数表示的差分。 也就是说,从差分的绝对值中减去1,然后将得到的这个无模整数常数变换为uint32型的值,最后,在这个值上取异或,就可以得到最终的参数值。

这样做的原理也不复杂。 简单地说,这种方式的结果值的补数与用前者的方法得到的值的补数相同,所以这两种方式是等价的。 由于整数在计算机中已知是作为补数存在的,所以这里结果值的补数相同就意味着公式的等价

交换和更换操作的比较有什么不同? 比较操作即CAS操作是有条件交换操作,仅在满足条件时进行值的交换。

交换是指将新值赋给变量,然后返回变量的旧值。

进行CAS操作时,函数首先判断被操作变量的当前值是否与我们期待的旧值相等。 如果等于,则为变量赋予新值,返回true以指示已进行交换操作。 否则忽略更换操作,返回false。

可以看到,CAS操作不是单个操作,而是操作的组合。 这和其他原子操作不同。 正因为如此,其用途更为广泛。 例如,如果将其与for语句组合使用,可以实现简单的自旋锁定(spinlock )。

for { if atomic.compareandswapint 32 (num 2,10,0 ) ) fmt.println (' thesecondnumberhasgonetozero.' ) break ) time.ssse

方法目前只支持int类型

import(fmt ) sync ) sync/atomic ) varxint 32 varwgsync.waitgroupfuncadd ) { for i :=0; i5000; I{/x=x1atomic.addint32(x,1 ) } defer wg.Done ) }func main ) ) WG.add )2)//分别为5000 go add ) ) go add )

chan struct{}, 2) num := int32(0) fmt.Printf("The number: %dn", num) go func() { // 定时增加num的值。 defer func() { sign <- struct{}{} }() for { time.Sleep(time.Millisecond * 500) newNum := atomic.AddInt32(&num, 2) fmt.Printf("The number: %dn", newNum) if newNum == 10 { break } } }() go func() { // 定时检查num的值,如果等于10就将其归零。 defer func() { sign <- struct{}{} }() for { if atomic.CompareAndSwapInt32(&num, 10, 0) { fmt.Println("The number has gone to zero.") break } time.Sleep(time.Millisecond * 500) } }() <-sign <-sign} atomic.value

atomic.Value分为两个操作,通过Store()存储Value,通过Load()来读取Value的值.

package mainimport ( "fmt" "sync/atomic")type Value struct { key string Val interface{}}type Noaway struct { Movies atomic.Value Total atomic.Value}func NewNoaway() *Noaway { n := new(Noaway) n.Movies.Store(&Value{key: "movie", Val: "Wolf Warrior 2"}) n.Total.Store("123") return n}func main() { n := NewNoaway() val := n.Movies.Load().(*Value) total := n.Total.Load().(string) fmt.Printf("%#v --- %#vn", val, total)} 如何用好atomic.value

第一条规则,不能用原子值存储nil。

也就是说,我们不能把nil作为参数值传入原子值的Store方法,否则就会引发一个 panic。

这里要注意,如果有一个接口类型的变量,它的动态值是nil,但动态类型却不是nil,那么它的值就不等于nil。我在前面讲接口的时候和你说明过这个问题。正因为如此,这样一个变量的值是可以被存入原子值的。

第二条规则,我们向原子值存储的第一个值,决定了它今后能且只能存储哪一个类型的值。

例如,我第一次向一个原子值存储了一个string类型的值,那我在后面就只能用该原子值来存储字符串了。如果我又想用它存储结构体,那么在调用它的Store方法的时候就会引发一个 panic。这个 panic 会告诉我,这次存储的值的类型与之前的不一致。

你可能会想:我先存储一个接口类型的值,然后再存储这个接口的某个实现类型的值,这样是不是可以呢?

很可惜,这样是不可以的,同样会引发一个 panic。因为原子值内部是依据被存储值的实际类型来做判断的。所以,即使是实现了同一个接口的不同类型,它们的值也不能被先后存储到同一个原子值中。

遗憾的是,我们无法通过某个方法获知一个原子值是否已经被真正使用,并且,也没有办法通过常规的途径得到一个原子值可以存储值的实际类型。这使得我们误用原子值的可能性大大增加,尤其是在多个地方使用同一个原子值的时候。

下面,我给你几条具体的使用建议。

不要把内部使用的原子值暴露给外界。比如,声明一个全局的原子变量并不是一个正确的做法。这个变量的访问权限最起码也应该是包级私有的。

如果不得不让包外,或模块外的代码使用你的原子值,那么可以声明一个包级私有的原子变量,然后再通过一个或多个公开的函数,让外界间接地使用到它。注意,这种情况下不要把原子值传递到外界,不论是传递原子值本身还是它的指针值。

如果通过某个函数可以向内部的原子值存储值的话,那么就应该在这个函数中先判断被存储值类型的合法性。若不合法,则应该直接返回对应的错误值,从而避免 panic 的发生。

如果可能的话,我们可以把原子值封装到一个数据类型中,比如一个结构体类型。这样,我们既可以通过该类型的方法更加安全地存储值,又可以在该类型中包含可存储值的合法类型信息。

除了上述使用建议之外,我还要再特别强调一点:尽量不要向原子值中存储引用类型的值。因为这很容易造成安全漏洞。请看下面的代码:

var box6 atomic.Valuev6 := []int{1, 2, 3}box6.Store(v6)v6[1] = 4 // 注意,此处的操作不是并发安全的!

我把一个[]int类型的切片值v6, 存入了原子值box6。注意,切片类型属于引用类型。所以,我在外面改动这个切片值,就等于修改了box6中存储的那个值。这相当于绕过了原子值而进行了非并发安全的操作。那么,应该怎样修补这个漏洞呢?可以这样做:

store := func(v []int) { replica := make([]int, len(v)) copy(replica, v) box6.Store(replica)}store(v6)v6[2] = 5 // 此处的操作是安全的

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。