From 36ff408b0b5711202e739beb006141f3d25bcaa4 Mon Sep 17 00:00:00 2001 From: Robert Landers Date: Sat, 22 Nov 2025 16:49:14 +0100 Subject: [PATCH] fix latency Signed-off-by: Robert Landers --- frankenphp.go | 12 +++++++----- go.mod | 1 + threadregular.go | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/frankenphp.go b/frankenphp.go index 4b5c0972..c63a8e80 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -35,8 +35,8 @@ import ( "syscall" "time" "unsafe" - // debug on Linux - //_ "github.com/ianlancetaylor/cgosymbolizer" + + "golang.org/x/sync/semaphore" ) type contextKeyStruct struct{} @@ -307,9 +307,11 @@ func Init(options ...Option) error { return err } - regularRequestChan = make(chan contextHolder, opt.numThreads-workerThreadCount) - regularThreads = make([]*phpThread, 0, opt.numThreads-workerThreadCount) - for i := 0; i < opt.numThreads-workerThreadCount; i++ { + numRegularThreads := opt.numThreads - workerThreadCount + regularRequestChan = make(chan contextHolder) + regularSemaphore = semaphore.NewWeighted(int64(numRegularThreads)) + regularThreads = make([]*phpThread, 0, numRegularThreads) + for i := 0; i < numRegularThreads; i++ { convertToRegularThread(getInactivePHPThread()) } diff --git a/go.mod b/go.mod index 51b37f30..a4484359 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( go.uber.org/zap v1.27.0 go.uber.org/zap/exp v0.3.0 golang.org/x/net v0.47.0 + golang.org/x/sync v0.18.0 ) require ( diff --git a/threadregular.go b/threadregular.go index b01c060d..bd2898ab 100644 --- a/threadregular.go +++ b/threadregular.go @@ -2,7 +2,10 @@ package frankenphp import ( "context" + "runtime" "sync" + + "golang.org/x/sync/semaphore" ) // representation of a non-worker PHP thread @@ -19,6 +22,7 @@ var ( regularThreads []*phpThread regularThreadMu = &sync.RWMutex{} regularRequestChan chan contextHolder + regularSemaphore *semaphore.Weighted // FIFO admission control ) func convertToRegularThread(thread *phpThread) { @@ -100,6 +104,16 @@ func (handler *regularThread) afterRequest() { func handleRequestWithRegularPHPThreads(ch contextHolder) error { metrics.StartRequest() + // yield to ensure this goroutine doesn't end up on the same P queue + runtime.Gosched() + + // Enforce FIFO ordering of requests + if err := regularSemaphore.Acquire(ch.ctx, 1); err != nil { + ch.frankenPHPContext.reject(err) + return err + } + defer regularSemaphore.Release(1) + select { case regularRequestChan <- ch: // a thread was available to handle the request immediately