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