github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/network/priorityqueue/priorityqueue.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:47</date>
    10  //</624342672693268480>
    11  
    12  
    13  //包优先级队列实现基于通道的优先级队列
    14  //在任意类型上。它提供了一个
    15  //一个自动操作循环,将一个函数应用于始终遵守的项
    16  //他们的优先权。结构只是准一致的,即如果
    17  //优先项是自动停止的,保证有一点
    18  //当没有更高优先级的项目时,即不能保证
    19  //有一点低优先级的项目存在
    20  //但更高的不是
    21  
    22  package priorityqueue
    23  
    24  import (
    25  	"context"
    26  	"errors"
    27  )
    28  
    29  var (
    30  	errContention  = errors.New("queue contention")
    31  	errBadPriority = errors.New("bad priority")
    32  
    33  	wakey = struct{}{}
    34  )
    35  
    36  //PriorityQueue是基本结构
    37  type PriorityQueue struct {
    38  	queues []chan interface{}
    39  	wakeup chan struct{}
    40  }
    41  
    42  //New是PriorityQueue的构造函数
    43  func New(n int, l int) *PriorityQueue {
    44  	var queues = make([]chan interface{}, n)
    45  	for i := range queues {
    46  		queues[i] = make(chan interface{}, l)
    47  	}
    48  	return &PriorityQueue{
    49  		queues: queues,
    50  		wakeup: make(chan struct{}, 1),
    51  	}
    52  }
    53  
    54  //运行是从队列中弹出项目的永久循环
    55  func (pq *PriorityQueue) Run(ctx context.Context, f func(interface{})) {
    56  	top := len(pq.queues) - 1
    57  	p := top
    58  READ:
    59  	for {
    60  		q := pq.queues[p]
    61  		select {
    62  		case <-ctx.Done():
    63  			return
    64  		case x := <-q:
    65  			f(x)
    66  			p = top
    67  		default:
    68  			if p > 0 {
    69  				p--
    70  				continue READ
    71  			}
    72  			p = top
    73  			select {
    74  			case <-ctx.Done():
    75  				return
    76  			case <-pq.wakeup:
    77  			}
    78  		}
    79  	}
    80  }
    81  
    82  //push将项目推送到priority参数中指定的适当队列
    83  //如果给定了上下文,它将一直等到推送该项或上下文中止为止。
    84  //否则,如果队列已满,则返回errCompetition
    85  func (pq *PriorityQueue) Push(ctx context.Context, x interface{}, p int) error {
    86  	if p < 0 || p >= len(pq.queues) {
    87  		return errBadPriority
    88  	}
    89  	if ctx == nil {
    90  		select {
    91  		case pq.queues[p] <- x:
    92  		default:
    93  			return errContention
    94  		}
    95  	} else {
    96  		select {
    97  		case pq.queues[p] <- x:
    98  		case <-ctx.Done():
    99  			return ctx.Err()
   100  		}
   101  	}
   102  	select {
   103  	case pq.wakeup <- wakey:
   104  	default:
   105  	}
   106  	return nil
   107  }
   108