Skip to content

negrel/conc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

36 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

structured concurrency schema

conc - Structured concurrency for Go

Go doc go report card license card PRs welcome card Go version card

conc is a structured concurrency library for Go that provides a safer, more intuitive approach to concurrent programming.

By emphasizing proper resource management, error handling, and execution flow, conc helps developers write concurrent code that is less error-prone, easier to reason about, and aligned with established best practices.

go get github.com/negrel/conc

Predictable code flow

conc is based on nursery as described in this blog post.

Idea behind nursery is that routines are scoped to a block that returns when all goroutines are done. This way, code flow remains sequential outside before and after the block. Here is an example:

func main() {
	conc.Block(func(n conc.Nursery) error {
		// Spawn a goroutine.
		n.Go(func() error {
			return nil
		})

		// Spawn another goroutine.
		n.Go(func() error {
			time.Sleep(2 * time.Second)
			return nil
		})

		// Sleep before returning.
		time.Sleep(time.Second)
		return nil
	})
	// Once block returns (here after 2 seconds), you're guaranteed that there is no
	// goroutine leak.
	// ...
}

Here is the definition of the Nursery interface:

type Nursery interface {
	context.Context
	Go(func() error)
}

It is a simple extension to context.Context that allows spawning routines.

Block and Nursery are the core of the entire library.

Explicit goroutines "leak"

Now, let's say you want to write a function spawning routines that outlives it. You can pass Nursery as a parameter making the leak explicit:

func workHard(n conc.Nursery) {
	n.Go(func() error {
		return longWork(n)
	})

	n.Go(func() error {
		return longerWork(n)
	})
}

And more...

  • Graceful panics and errors handling
  • Context integration for deadlines and cancellation
  • Limit maximum number of goroutine used by a block
  • Goroutines are pool allocated to improve efficiency
  • Dependency free

Performance

Here, an operation means spawning 100 goroutines:

$ cd bench/
$ go test -v -bench=./... -benchmem ./...
goos: linux
goarch: amd64
pkg: github.com/negrel/conc/bench
cpu: AMD Ryzen 7 7840U w/ Radeon  780M Graphics
BenchmarkNursery
BenchmarkNursery/EmptyBlock
BenchmarkNursery/EmptyBlock-16   1367210               914.3 ns/op           625 B/op         11 allocs/op
BenchmarkNursery/WithRoutines/NoWork
BenchmarkNursery/WithRoutines/NoWork-16                    26823             43909 ns/op            1514 B/op         65 allocs/op
BenchmarkNursery/WithRoutines/Nested/NoWork
BenchmarkNursery/WithRoutines/Nested/NoWork-16             18189             69416 ns/op            3623 B/op        147 allocs/op
BenchmarkNursery/WithRoutines/1msWork
BenchmarkNursery/WithRoutines/1msWork-16                     940           1300306 ns/op           11941 B/op        211 allocs/op
BenchmarkNursery/WithRoutines/1-10msWork
BenchmarkNursery/WithRoutines/1-10msWork-16                  123           9681105 ns/op           12427 B/op        292 allocs/op
BenchmarkNursery/WithRoutines/Error
BenchmarkNursery/WithRoutines/Error-16                     26767             44257 ns/op            1485 B/op         65 allocs/op
BenchmarkSourceGraphConc
BenchmarkSourceGraphConc/EmptyPool
BenchmarkSourceGraphConc/EmptyPool-16                   13450243                85.45 ns/op          176 B/op          2 allocs/op
BenchmarkSourceGraphConc/WithRoutines/NoWork
BenchmarkSourceGraphConc/WithRoutines/NoWork-16            48522             23928 ns/op            1835 B/op         84 allocs/op
BenchmarkSourceGraphConc/WithRoutines/1msWork
BenchmarkSourceGraphConc/WithRoutines/1msWork-16                     966           1239140 ns/op           13776 B/op        302 allocs/op
BenchmarkSourceGraphConc/WithRoutines/1-10msWork
BenchmarkSourceGraphConc/WithRoutines/1-10msWork-16                  123           9625635 ns/op           14030 B/op        372 allocs/op
BenchmarkGo
BenchmarkGo/WithRoutines/NoWork
BenchmarkGo/WithRoutines/NoWork-16                                 84024             14240 ns/op            1600 B/op        100 allocs/op
BenchmarkGo/WithRoutines/Nested/NoWork
BenchmarkGo/WithRoutines/Nested/NoWork-16                          81360             14497 ns/op            3199 B/op        199 allocs/op
BenchmarkGo/WithRoutines/1msWork
BenchmarkGo/WithRoutines/1msWork-16                                59904             18651 ns/op           11215 B/op        200 allocs/op
BenchmarkGo/WithRoutines/1-10msWork
BenchmarkGo/WithRoutines/1-10msWork-16                             51703             21088 ns/op           11069 B/op        190 allocs/op
PASS
ok      github.com/negrel/conc/bench    22.347s

Contributing

If you want to contribute to conc to add a feature or improve the code contact me at [email protected], open an issue or make a pull request.

🌠 Show your support

Please give a ⭐ if this project helped you!

buy me a coffee

πŸ“œ License

MIT Β© Alexandre Negrel