init repo
This commit is contained in:
69
mailbox.go
Normal file
69
mailbox.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package actor
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// mailbox owns the single-consumer handoff and scheduling policy. running also
|
||||
// covers the interval after scheduling and before the task starts executing.
|
||||
type mailbox[T any] struct {
|
||||
queue *queue[T]
|
||||
invoker invoker[T]
|
||||
dispatcher Dispatcher
|
||||
task func()
|
||||
batchSize int
|
||||
yield func()
|
||||
running atomic.Bool
|
||||
}
|
||||
|
||||
func newMailbox[T any](q *queue[T], invoke invoker[T], batchSize int, dispatcher Dispatcher) *mailbox[T] {
|
||||
m := &mailbox[T]{
|
||||
queue: q,
|
||||
invoker: invoke,
|
||||
dispatcher: dispatcher,
|
||||
batchSize: batchSize,
|
||||
yield: runtime.Gosched,
|
||||
}
|
||||
// Reuse this method value for every scheduling request, without allocating
|
||||
// a closure on each Send or ownership handoff.
|
||||
m.task = m.drain
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *mailbox[T]) send(message T) {
|
||||
m.queue.push(message)
|
||||
m.tryRun()
|
||||
}
|
||||
|
||||
func (m *mailbox[T]) tryRun() {
|
||||
if m.running.CompareAndSwap(false, true) {
|
||||
m.dispatcher.Schedule(m.task)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *mailbox[T]) drain() {
|
||||
processed := 0
|
||||
for {
|
||||
batch := m.queue.takeBatch(m.batchSize, m.yield)
|
||||
if batch == nil {
|
||||
m.running.Store(false)
|
||||
// A producer may have published while running was still true.
|
||||
// Either we reclaim ownership or that producer schedules a task.
|
||||
if m.queue.empty() || !m.running.CompareAndSwap(false, true) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
for n := batch; n != nil; {
|
||||
message, next := m.queue.pop(n)
|
||||
n = next
|
||||
m.invoker.receive(message)
|
||||
processed++
|
||||
if processed == m.batchSize {
|
||||
processed = 0
|
||||
m.yield()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user