ThreadManager provides a simple way to manage concurrent threads in Go.
Below you will find basic infomation on Golang concurrency and how to use it effectively as well as a description of the ThreadManager package with its methods, exmaples and use cases.
Go is designed with concurrency in mind. Concurrency refers to executing multiple tasks simultaneously by dividing them into separate processes that can run independently. Here's an overview of concurrency in Go and how to use it effectively.
The basic unit of concurrency in Go is the goroutine. A goroutine is a lightweight thread that runs concurrently with other goroutines in the same address space. To start a goroutine, simply put the go
keyword in front of a function call:
go doSomething()
This will execute doSomething() concurrently in a new goroutine. The main code will continue executing without waiting for the goroutine to finish.
Goroutines need a way to communicate with each other. This is done through channels. A channel is a pipe that passes a value from one goroutine to another. For example:
ch := make(chan int)
go func() {
ch <- 42 // Send 42 to the channel
}()
i := <-ch // Receive from the channel
This passes the integer 42 from one goroutine to the main goroutine through the channel ch.
Channels are typed, so you can only pass a certain type of value through a particular channel. By default sends and receives block until both sides of the channel are ready. This allows goroutines to synchronize without explicit locks or condition variables.
The sync package provides a WaitGroup type that allows you to wait for a collection of goroutines to finish executing. This is useful when you spawn several concurrent tasks and want to wait for them all to complete before moving on.
For example:
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1) // Increment wait group counter
go func(item) {
defer wg.Done() // Decrement counter when goroutine exits
// Process item
}(item)
}
wg.Wait() // Block until counter reaches zero
The WaitGroup allows you to wait for concurrent goroutines in a simple way.
To synchronize access to shared memory in Go (such as a global variable), you can use a mutex from the sync package. This will lock access to the shared variable so only one goroutine at a time can read or write to it.
For example:
var count int
var mutex sync.Mutex
func Increment() {
mutex.Lock()
count++
mutex.Unlock()
}
This ensures count is incremented atomically without conflicts between goroutines.
Here are some good opportunities to introduce concurrency in your Go programs:
- Network/IO-bound tasks - launching a goroutine to handle slow IO in the background
- Parallelizing computation - divide work across CPU cores
- Handling requests concurrently - launch a goroutine per request
Overusing concurrency can add unnecessary complexity so only reach for it when you have an appropriate use case. Overall it's a powerful tool for building efficient and scalable applications in Go.
Import the package:
import "github.com/AndrewDonelson/threadmanager"
Create a new ThreadManager:
tm := threadmanager.New()
Add a task to the ThreadManager:
tm.AddThread("thread1", func() {
// do work
}, 1000) // 1 second timing
The function can accept parameters:
tm.AddThread("thread2", func(msg string) {
fmt.Println(msg)
}, 500)
Start threads by name:
tm.StartThread("thread1")
tm.StartThread("thread2", "Hello!")
Stop threads gracefully:
tm.StopThread("thread1")
Wait for threads to finish:
tm.wg.Wait()
Thread Struct
The Thread struct contains:
Name - unique name Fn - function to run Timing - milliseconds between invocations Logs - log messages
Examples
Run two threads with different intervals:
tm := threadmanager.New()
tm.AddThread("thread1", func() {
// do work
}, 1500) // 1.5 second interval
tm.AddThread("thread2", func() {
// do other work
}, 250) // 0.25 second interval
tm.StartThread("thread1")
tm.StartThread("thread2")
// Threads run concurrently
tm.StopThread("thread1")
tm.StopThread("thread2")
Pass parameters to threads:
tm.AddThread("print", func(msg string) {
fmt.Println(msg)
}, 0)
tm.StartThread("print", "Hello World!")