Skip to content

Commit

Permalink
all: add lower limit to the number of threads
Browse files Browse the repository at this point in the history
  • Loading branch information
changkun committed Oct 4, 2020
1 parent 151d837 commit b61d4ae
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 15 deletions.
26 changes: 14 additions & 12 deletions mkill.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import (
)

var (
pid = os.Getpid()
maxThread = int32(runtime.NumCPU()) + 2 // 2 meaning runtime sysmon thread + template thread
interval = time.Second
debug = false
pid = os.Getpid()
minThreads = int32(runtime.NumCPU()) + 2 // minimum number of threads required by the runtime
maxThreads = int32(runtime.NumCPU()) + 2 // 2 meaning runtime sysmon thread + template thread
interval = time.Second
debug = false
)

// NumM returns the number of running threads.
Expand All @@ -41,14 +42,15 @@ func NumM() int {
}

// GOMAXTHREADS sets the maximum number of system threads that allowed in a Go program
// and returns the previous setting. If n < 1, it does not change the current setting.
// The default allowed number of threads of a program is runtime.NumCPU() + 2.
// and returns the previous setting. If n is lower than minimum required number of threads,
// it does not change the current setting.
// The minimum allowed number of threads of a program is runtime.NumCPU() + 2.
func GOMAXTHREADS(n int) int {
if n < 1 {
return int(atomic.LoadInt32(&maxThread))
if n < int(minThreads) {
return int(atomic.LoadInt32(&maxThreads))
}

return int(atomic.SwapInt32(&maxThread, int32(n)))
return int(atomic.SwapInt32(&maxThreads, int32(n)))
}

// Wait waits until the number of threads meet the GOMAXTHREADS settings.
Expand Down Expand Up @@ -82,7 +84,7 @@ func checkwork() {
func init() {
checkwork()
if debug {
fmt.Printf("mkill: pid %v, maxThread %v, interval %v\n", pid, maxThread, interval)
fmt.Printf("mkill: pid %v, maxThread %v, interval %v\n", pid, maxThreads, interval)
}

wg := sync.WaitGroup{}
Expand All @@ -92,10 +94,10 @@ func init() {
select {
case <-t.C:
n := NumM()
nkill := int32(n) - atomic.LoadInt32(&maxThread)
nkill := int32(n) - atomic.LoadInt32(&maxThreads)
if nkill <= 0 {
if debug {
fmt.Printf("mkill: checked #threads total %v / max %v\n", n, maxThread)
fmt.Printf("mkill: checked #threads total %v / max %v\n", n, maxThreads)
}
continue
}
Expand Down
20 changes: 17 additions & 3 deletions mkill_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ package mkill_test
import (
"context"
"fmt"
"runtime"
"sync"
"testing"
"time"

Expand All @@ -17,17 +19,29 @@ func TestMKill(t *testing.T) {
mkill.GOMAXTHREADS(10)

// create a lot of threads by sleep gs
wg := sync.WaitGroup{}
wg.Add(100000)
for i := 0; i < 100000; i++ {
go func() {
time.Sleep(time.Second * 10)
time.Sleep(time.Second * 1)
wg.Done()
}()
}

ctx, cancel := context.WithTimeout(context.Background(), time.Second*100)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
ok := mkill.Wait(ctx)
if !ok {
t.Fatal("mkill failed in 100s")
t.Fatal("mkill failed in 10s")
}
wg.Wait()
}

func TestMinThreads(t *testing.T) {
old := mkill.GOMAXTHREADS(0)
n := runtime.NumCPU()
if mkill.GOMAXTHREADS(n-1) != old {
t.Fatalf("number of threads is less than required in the runtime")
}
}

Expand Down

0 comments on commit b61d4ae

Please sign in to comment.