func NewSemaphore(capacity int, rampUp time.Duration) *Semaphore {
	s := Semaphore{
		lockDone: make(chan struct{}),
		lockLock: make(chan struct{}),
		rampUp:   rampUp,
	}

	// if the rampup time is less than 1 then return immediately
	if rampUp < 1 {
		s.s = make(chan struct{}, capacity)
	} else {
		s.s = make(chan struct{}, 1)
		go s.rampUpThreads(capacity, rampUp)
	}

	s.resizeUnlock()

	return &s
}
func NewSemaphore(capacity int, rampUp time.Duration) *Semaphore {
	s := Semaphore{
		lockDone: make(chan struct{}),
		lockLock: make(chan struct{}),
		rampUp:   rampUp,
	}

	// if the rampup time is less than 1 then return immediately
	if rampUp < 1 {
		s.s = make(chan struct{}, capacity)
	} else {
		s.s = make(chan struct{}, 1)
		go s.rampUpThreads(capacity, rampUp)
	}

	s.resizeUnlock()

	return &s
}
// NewSemaphore is used to create a new semaphore, initalised with a capacity
// this controls the number of locks which can be active at any one time.