func (s *Simulation) HandleParallel() {
	event := s.Pop()
	if event == nil {
		runtime.Gosched()
		return
	}
	eventTime := event.timestamp
	events := []*Event{}
	for ; event != nil && event.timestamp == eventTime; event = s.Pop() {
		events = append(events, event)
	}
	if event != nil {
		s.Push(event)
	}
	for _, event := range events {
		for _, observer := range s.observers {
			observer.Receive(event)
		}
	}
	s.timeMutex.Lock()
	s.time = events[0].timestamp
	s.timeMutex.Unlock()
	special := []*Event{}
	rest := []*Event{}
	for _, event := range events {
		if event == nil || event.Receiver() == nil {
			continue
		}
		if s.check(event.Receiver()) {
			rest = append(rest, event)
		} else {
			special = append(special, event)
		}
	}
	events = rest
	for _, event := range special {
		s.processEvent(event)
	}
	groups := make(map[Receiver][]*Event)
	for _, event := range events {
		receiver := event.Receiver()
		if receiver == nil {
			continue
		}
		if _, ok := groups[receiver]; !ok {
			groups[receiver] = []*Event{}
		}
		groups[receiver] = append(groups[receiver], event)
	}
	switch {
	case len(groups) == 0:
	case len(groups) == 1:
		for _, group := range groups {
			for _, event := range group {
				s.processEvent(event)
			}
		}
	default:
		done := make(chan bool)
		routines := 0
		for _, group := range groups {
			routines += 1
			s.processGroup(group, done)
		}
		for i := 0; i < routines; i++ {
			<-done
		}
	}
	return
}
Handling events in parallel.

We allow parallel exectution following the next pipeline:
- pop all events with the time-stamp equal with now
- group all these events in event groups by the receiver address
- execute the receivers in parallel
- wait for all receivers to finish their execution
package events
import (
	"fmt"
	"reflect"
	"runtime"
	"sync"
)
type Simulation struct {
	observers []Observer
	stopped   chan interface{}
	timeMutex *sync.RWMutex
	time      int
	parallel bool
	check    func(Receiver) bool
	EventQueue
}
const maxRegisterQueue int = 50
const minRegisterQueue int = 10
const settleTime int = 200
func check(r Receiver) bool {
	return reflect.TypeOf(r).String() == "*underlay.shortestPathRouter"
}
func NewLazySimulation() (s *Simulation) {
	s = &Simulation{
		observers: make([]Observer, 0),
		stopped:   make(chan interface{}, 1),
		timeMutex: new(sync.RWMutex),
		time:      0,
		check:     check,
		parallel:   false,
		EventQueue: NewLazyEventQueue(),
	}
	return
}
func (s *Simulation) SetParallel(parallel bool) {
	s.parallel = parallel
}
func (s *Simulation) RegisterObserver(eventObserver Observer) {
	s.observers = append(s.observers, eventObserver)
}
func (s *Simulation) Time() int {
	s.timeMutex.RLock()
	defer s.timeMutex.RUnlock()
	return s.time
}
func (s *Simulation) Stop() {
	s.stopped <- nil
}
func (s *Simulation) processEvent(event *Event) {
	newEvent := event.receiver.Receive(event)
	if newEvent != nil {
		s.Push(newEvent)
	}
}
func (s *Simulation) Run() {
	fmt.Println("Starting the simulation.")
	handler := s.Handle
	if s.parallel {
		handler = s.HandleParallel
	}
	settled := false
	for {
		select {
		case <-s.stopped:
			break
		default:
			if !settled && s.Time() < 200 {
				s.Handle()
			} else {
				settled = true
				handler()
			}
		}
	}
}
func (s *Simulation) Handle() {
	if event := s.Pop(); event != nil {
		for _, observer := range s.observers {
			observer.Receive(event)
		}
		s.timeMutex.Lock()
		s.time = event.timestamp
		s.timeMutex.Unlock()
		receiver := event.receiver
		if receiver == nil {
			return
		}
		newEvent := receiver.Receive(event)
		if newEvent != nil {
			s.Push(newEvent)
		}
	} else {
		runtime.Gosched()
	}
	return
}
func (s *Simulation) processGroup(group []*Event, done chan bool) {
	toProcess := []*Event{}
	for _, event := range group {
		toProcess = append(toProcess, event)
	}
	go func() {
		for _, event := range toProcess {
			s.processEvent(event)
		}
		done <- true
	}()
}