源码中的超高性能取模

2021/7/8 17:36:18

本文主要是介绍源码中的超高性能取模,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

今天在看一个golang的ringbuffer的源码时看到一段看不懂的代码

https://github.com/Workiva/go-datastructures/blob/c466da296827daa1e1efba14c912e2802533fe7f/queue/ring.go#L96

func (rb *RingBuffer) init(size uint64) {
	size = roundUp(size)
	rb.nodes = make(nodes, size)
	for i := uint64(0); i < size; i++ {
		rb.nodes[i] = node{position: i}
	}
	rb.mask = size - 1 // so we don't have to do this with every put/get operation
}

// Put adds the provided item to the queue.  If the queue is full, this
// call will block until an item is added to the queue or Dispose is called
// on the queue.  An error will be returned if the queue is disposed.
func (rb *RingBuffer) Put(item interface{}) error {
	_, err := rb.put(item, false)
	return err
}

// Offer adds the provided item to the queue if there is space.  If the queue
// is full, this call will return false.  An error will be returned if the
// queue is disposed.
func (rb *RingBuffer) Offer(item interface{}) (bool, error) {
	return rb.put(item, true)
}

func (rb *RingBuffer) put(item interface{}, offer bool) (bool, error) {
	var n *node
	pos := atomic.LoadUint64(&rb.queue)
L:
	for {
		if atomic.LoadUint64(&rb.disposed) == 1 {
			return false, ErrDisposed
		}

		n = &rb.nodes[pos&rb.mask]
		seq := atomic.LoadUint64(&n.position)
		switch dif := seq - pos; {
		case dif == 0:
			if atomic.CompareAndSwapUint64(&rb.queue, pos, pos+1) {
				break L
			}
		case dif < 0:
			panic(`Ring buffer in a compromised state during a put operation.`)
		default:
			pos = atomic.LoadUint64(&rb.queue)
		}

		if offer {
			return false, nil
		}

		runtime.Gosched() // free up the cpu before the next iteration
	}

	n.data = item
	atomic.StoreUint64(&n.position, pos+1)
	return true, nil
}

rb.mask = size - 1 
n = &rb.nodes[pos&rb.mask]

这两行代码从意思上理解是要取模, 因为是ringbuffer嘛, 所以肯定要取模, 但是为啥他的取模这么简单?
分析代码得到, size肯定是2的倍数, 结果发现size-1 & pos 就 等于 pos % size
例如:size = 8
那么mask = 0b111
比如 pos = 9, 那么 0b111 & 0b1001 = 1就是取模的值
原理就是2的倍数减1肯定是全是1的二进制位, &运算正好就会去除高位, 所以结果就等于取模的值了,
顿时觉得大佬写的代码真



这篇关于源码中的超高性能取模的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程