Go · Parallelism

Parallelism

import "github.com/ashvardanian/NumKong" 8.0.0-rc.1 · b1f866ab

WorkerPool provides pre-pinned goroutines with pre-configured SIMD state. Create once, reuse across batch calls, close when done. The pool amortizes Device.ConfigureThread + LockOSThread cost across all batch operations.

package main

import (
	"fmt"

	nk "github.com/ashvardanian/NumKong/golang"
)

func main() {
	columns, depth, totalQueries := 1024, 128, 10000

	db := make([]float32, columns*depth)
	queries := make([]float32, totalQueries*depth)
	for i := range db { db[i] = float32(i%7) * 0.1 }
	for i := range queries { queries[i] = float32(i%11) * 0.1 }

	dbPacked := nk.NewDotsPackedMatrixF32(db, columns, depth)

	// Create a reusable pool (defaults to GOMAXPROCS workers)
	pool := nk.NewWorkerPool(8)
	defer pool.Close()

	// Packed batch operations dispatch to the pool
	results := make([]float64, totalQueries*columns)
	dbPacked.DotsF32WithPool(queries, results, totalQueries, pool)

	// Angular and Euclidean distances use the same pool
	angResults := make([]float64, totalQueries*columns)
	dbPacked.AngularsF32WithPool(queries, angResults, totalQueries, pool)

	fmt.Println("first result row:", results[:columns])
}

Symmetric operations also support pool-based parallelism:

n, depth := 1000, 128
vectors := make([]float32, n*depth)
gram := make([]float64, n*n)

pool := nk.NewWorkerPool(0) // 0 = GOMAXPROCS
defer pool.Close()

nk.DotsSymmetricF32WithPool(vectors, n, depth, gram, pool)

For one-off parallel work without a pool, you can still use ConfigureThread directly:

go func() {
	enabled, _ := nk.CPU().CapabilitiesEnabled()
	unlock, _ := nk.CPU().ConfigureThread(enabled) // lock thread + configure SIMD
	defer unlock()                                 // release the OS thread on return
	nk.DotsPackedF32(queries, dbPacked, results, rows)
}()

API

StructWorkerPoolWorkerPool runs batch kernels on goroutines pinned to OS threads, each configuring its SIMD state once.3
matrix.go:19 ↗
type WorkerPool struct {
    // contains filtered or unexported fields
}

Create it with NewWorkerPool, reuse it across calls, and release it with WorkerPool.Close.

NewWorkerPoolNewWorkerPool starts n pinned workers, or GOMAXPROCS workers when n is not positive.
matrix.go:25 ↗
func NewWorkerPool(n int) *WorkerPool
CloseClose stops every worker and waits for it to exit.
matrix.go:52 ↗
func (p *WorkerPool) Close()
SizeSize returns the number of workers in the pool.
matrix.go:49 ↗
func (p *WorkerPool) Size() int