Provides some convenient API, includes Goid(), AllGoid(), and LocalStorage, which is a goroutine's local storage, just like ThreadLocal in other languages.

routine

Build Status codecov Go doc

中文版

routine encapsulates and provides some easy-to-use, high-performance goroutine context access interfaces, which can help you access coroutine context information more elegantly, but you may also open Pandora's Box.

Introduce

The Golang language has been sparing no effort to shield developers from the concept of coroutine context from the beginning of its design, including the acquisition of coroutine goid, the state of the coroutine within the process, and the storage of coroutine context.

If you have used other languages such as C++/Java/..., then you must be familiar with ThreadLocal, and after starting to use Golang, you will definitely feel confused and distressed by the lack of convenient functions similar to ThreadLocal . Of course, you can choose to use Context, let it carry all the context information, appear in the first input parameter of all functions, and then shuttle around in your system.

The core goal of routine is to open up another path: to introduce goroutine local storage into the world of Golang , and at the same time expose the coroutine information to meet the needs of some people.

Usage & Demo

This chapter briefly introduces how to install and use the routine library.

Install

go get github.com/go-eden/routine

Use goid

The following code simply demonstrates the use of routine.Goid() and routine.AllGoids():

package main

import (
	"fmt"
	"github.com/go-eden/routine"
	"time"
)

func main() {
	go func() {
		time.Sleep(time.Second)
	}()
	goid := routine.Goid()
	goids := routine.AllGoids()
	fmt.Printf("curr goid: %d\n", goid)
	fmt.Printf("all goids: %v\n", goids)
}

In this example, the main function starts a new coroutine, so Goid() returns the main coroutine 1, and AllGoids() returns the main coroutine and coroutine 18:

curr goid: 1
all goids: [1 18]

Use LocalStorage

The following code simply demonstrates NewLocalStorage(), Set(), Get(), and cross-coroutine propagation of LocalStorage:

package main

import (
	"fmt"
	"github.com/go-eden/routine"
	"time"
)

var nameVar = routine.NewLocalStorage()

func main() {
	nameVar.Set("hello world")
	fmt.Println("name: ", nameVar.Get())

	// other goroutine cannot read nameVar
	go func() {
		fmt.Println("name1: ", nameVar.Get())
	}()

	// but, the new goroutine could inherit/copy all local data from the current goroutine like this:
	routine.Go(func() {
		fmt.Println("name2: ", nameVar.Get())
	})

	// or, you could copy all local data manually
	ic := routine.BackupContext()
	go func() {
		routine.InheritContext(ic)
		fmt.Println("name3: ", nameVar.Get())
	}()

	time.Sleep(time.Second)
}

The results of the upper example are:

name:  hello world
name1:  <nil>
name3:  hello world
name2:  hello world

API

This chapter introduces in detail all the interfaces encapsulated by the routine library, as well as their core functions and implementation methods.

Goid() (id int64)

Get the goid of the current goroutine.

Under normal circumstances, Goid() first tries to obtain it directly through go_tls. This operation has extremely high performance and the time-consuming is usually only one-fifth of rand.Int().

If an error such as version incompatibility occurs, Goid() will try to downgrade, that is, parse it from the runtime.Stack information. At this time, the performance will drop sharply by about a thousand times, but it can ensure that the function is normally available.

AllGoids() (ids []int64)

Get the goid of all active goroutine of the current process.

In go 1.15 and older versions, AllGoids() will try to parse and get all the coroutine information from the runtime.Stack information, but this operation is very inefficient and it is not recommended to use it in high-frequency logic. .

In versions after go 1.16, AllGoids() will directly read the global coroutine pool information of runtime through native, which has greatly improved performance, but considering the production environment There may be tens of thousands or millions of coroutines, so it is still not recommended to use it at high frequencies.

NewLocalStorage():

Create a new instance of LocalStorage, its design idea is very similar to the usage of ThreadLocal in other languages.

BackupContext() *ImmutableContext

Back up the local storage data of the current coroutine context. It is just an immutable structure that facilitates the transfer of context data.

InheritContext(ic *ImmutableContext)

Actively inherit the backed-up context local storage data, it will copy the data of other coroutines BackupContext() into the current coroutine context, thus supporting the contextual data propagation across coroutines.

Go(f func())

Start a new coroutine and automatically copy all the context local storage data of the current coroutine to the new coroutine. Its internal implementation consists of BackupContext() and InheritContext().

LocalStorage

Represents the context variable of the coroutine, and the supported functions include:

  • Get() (value interface{}): Get the variable value that has been set by the current coroutine.
  • Set(v interface{}) interface{}: Set the value of the context variable of the current coroutine, and return the old value that has been set before.
  • Del() (v interface{}): Delete the context variable value of the current coroutine and return the deleted old value.
  • Clear(): Thoroughly clean up the old value of this context variable saved in all coroutines.

Tip: The internal implementation of Get/Set/Del adopts a lock-free design. In most cases, its performance should be very stable and efficient.

Garbage Collection

The routine library internally maintains the global storages variable, which stores all the context variable information of the coroutine, and performs variable addressing mapping based on the goid of the coroutine and the ptr of the coroutine variable when reading and writing.

In the entire life cycle of a process, it may be created by destroying countless coroutines, so how to clean up the context variables of these dead coroutines?

To solve this problem, a global GCTimer is allocated internally by routine. This timer will be started when storages needs to be cleaned up. It scans and cleans up the context variables cached by dead coroutine in storages at regular intervals, so as to avoid possible hidden dangers of memory leaks.

License

MIT

Similar Resources

🐜🐜🐜 ants is a high-performance and low-cost goroutine pool in Go, inspired by fasthttp./ ants 是一个高性能且低损耗的 goroutine 池。

🐜🐜🐜 ants is a high-performance and low-cost goroutine pool in Go, inspired by fasthttp./ ants 是一个高性能且低损耗的 goroutine 池。

A goroutine pool for Go English | 🇨🇳 中文 📖 Introduction Library ants implements a goroutine pool with fixed capacity, managing and recycling a massi

Jan 2, 2023

A sync.WaitGroup with error handling and concurrency control

go-waitgroup How to use An package that allows you to use the constructs of a sync.WaitGroup to create a pool of goroutines and control the concurrenc

Dec 31, 2022

👷 Library for safely running groups of workers concurrently or consecutively that require input and output through channels

👷 Library for safely running groups of workers concurrently or consecutively that require input and output through channels

Examples Quickstart Multiple Go Workers Passing Fields Getting Started Pull in the dependency go get github.com/catmullet/go-workers Add the import to

Dec 1, 2022

🐝 A Highly Performant and easy to use goroutine pool for Go

🐝 A Highly Performant and easy to use goroutine pool for Go

gohive Package gohive implements a simple and easy to use goroutine pool for Go Features Pool can be created with a specific size as per the requireme

Sep 26, 2022

Go asynchronous simple function utilities, for managing execution of closures and callbacks

Go asynchronous simple function utilities, for managing execution of closures and callbacks

⚙️ gollback gollback - Go asynchronous simple function utilities, for managing execution of closures and callbacks 📖 ABOUT Contributors: Rafał Lorenz

Dec 29, 2022

Minimalistic and High-performance goroutine worker pool written in Go

pond Minimalistic and High-performance goroutine worker pool written in Go Motivation This library is meant to provide a simple way to limit concurren

Dec 22, 2022

:speedboat: a limited consumer goroutine or unlimited goroutine pool for easier goroutine handling and cancellation

Package pool Package pool implements a limited consumer goroutine or unlimited goroutine pool for easier goroutine handling and cancellation. Features

Jan 1, 2023

A simple and useful goroutine concurrent library.

Taskgroup A simple and useful goroutine concurrent library. Installation go get github.com/anthhub/taskgroup

May 19, 2021

Routines was a fixed number thread pool to process the user task, and it would respawn a corresponding new thread when panic

Routines Routines was a fixed number thread pool to process the user task, and it would respawn a corresponding new thread when panic. It supports the

Dec 16, 2021
Comments
  • NewLocalStorage does not support multiple instance

    NewLocalStorage does not support multiple instance

    Currently the NewLocalStorage doesn't support multiple instance, because the " type storage struct { }" is empty, need put one field is the storage struct.

  • 请问支持go1.17 arm64架构吗

    请问支持go1.17 arm64架构吗

    使用的时候报错如下: goroutine 1 [running, locked to thread]: runtime.throw({0x10226d3d6, 0x5}) /usr/local/go/src/runtime/panic.go:1198 +0x54 fp=0x14000068c60 sp=0x14000068c30 pc=0x10220db94 runtime.sigpanic() /usr/local/go/src/runtime/signal_unix.go:742 +0x1e4 fp=0x14000068ca0 sp=0x14000068c60 pc=0x102223e04 github.com/go-eden/routine.getGoidByNative() /Users/markma/go/pkg/mod/github.com/go-eden/[email protected]/routine_goid.go:75 +0x48 fp=0x14000068cd0 sp=0x14000068cb0 pc=0x10226c1f8 github.com/go-eden/routine.Goid() /Users/markma/go/pkg/mod/github.com/go-eden/[email protected]/routine_api.go:69 +0x20 fp=0x14000068cf0 sp=0x14000068cd0 pc=0x10226bec0 github.com/go-eden/routine.loadCurrentStore() /Users/markma/go/pkg/mod/github.com/go-eden/[email protected]/routine_storage.go:77 +0x20 fp=0x14000068dd0 sp=0x14000068cf0 pc=0x10226c720 github.com/go-eden/routine.(*storage).Clear(...) /Users/markma/go/pkg/mod/github.com/go-eden/[email protected]/routine_storage.go:70 github.com/go-eden/routine.NewLocalStorage() /Users/markma/go/pkg/mod/github.com/go-eden/[email protected]/routine_api.go:60 +0x24 fp=0x14000068df0 sp=0x14000068dd0 pc=0x10226be24 main.init() /Users/markma/GolandProjects/awesomeProject/main.go:8 +0x20 fp=0x14000068e10 sp=0x14000068df0 pc=0x10226ce20 runtime.doInit(0x102305aa0) /usr/local/go/src/runtime/proc.go:6498 +0x138 fp=0x14000068f70 sp=0x14000068e10 pc=0x10221edb8 runtime.main() /usr/local/go/src/runtime/proc.go:238 +0x22c fp=0x14000068fd0 sp=0x14000068f70 pc=0x10221032c runtime.goexit() /usr/local/go/src/runtime/asm_arm64.s:1133 +0x4 fp=0x14000068fd0 sp=0x14000068fd0 pc=0x10223b924

    go env 如下 GO111MODULE="on" GOARCH="arm64" GOBIN="/usr/local/go/bin" GOCACHE="/Users/markma/Library/Caches/go-build" GOENV="/Users/markma/Library/Application Support/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="arm64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/markma/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/markma/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/darwin_arm64" GOVCS="" GOVERSION="go1.17.1" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="/Users/markma/GolandProjects/awesomeProject/go.mod"

  • getAllGoidByNative中是否不应该过滤gDead

    getAllGoidByNative中是否不应该过滤gDead

    if runtimeReadgstatus(gp) == gDead || runtimeIsSystemGoroutine(gp, false) {
        continue
    }
    

    在系统调用/cgo/新建g的时候, g的状态也是gDead, 是否不应该在这里过滤掉gDead状态的g 因为这里的g状态虽然是dead,但等一会还是会恢复成runnable 如cgo调用

Floc: Orchestrate goroutines with ease.
Floc: Orchestrate goroutines with ease.

go-floc Floc: Orchestrate goroutines with ease. The goal of the project is to make the process of running goroutines in parallel and synchronizing the

Dec 8, 2022
Simply way to control goroutines execution order based on dependencies
Simply way to control goroutines execution order based on dependencies

Goflow Goflow is a simply package to control goroutines execution order based on dependencies. It works similar to async.auto from node.js async packa

Dec 8, 2022
Limits the number of goroutines that are allowed to run concurrently

Golang Concurrency Manager Golang Concurrency Manager package limits the number of goroutines that are allowed to run concurrently. Installation Run t

Dec 12, 2022
gpool - a generic context-aware resizable goroutines pool to bound concurrency based on semaphore.

gpool - a generic context-aware resizable goroutines pool to bound concurrency. Installation $ go get github.com/sherifabdlnaby/gpool import "github.c

Oct 31, 2022
Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive.
Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive.

Hunch Hunch provides functions like: All, First, Retry, Waterfall etc., that makes asynchronous flow control more intuitive. About Hunch Go have sever

Dec 8, 2022
go routine control, abstraction of the Main and some useful Executors.如果你不会管理Goroutine的话,用它
go routine control, abstraction of the Main and some useful Executors.如果你不会管理Goroutine的话,用它

routine Routine Architecture Quick Start package main import ( "log" "context" "github.com/x-mod/routine" ) func main(){ if err := routine.Main

Dec 6, 2022
A cross goroutine storage tool with very simple implementation and function.

Simple-goroutine-local is a cross goroutine storage tool with very simple implementation and function (the concept is similar to Java ThreadLocal). Ge

Jan 13, 2022
A safe way to execute functions asynchronously, recovering them in case of panic. It also provides an error stack aiming to facilitate fail causes discovery.

Async Provides a safe way to execute functions asynchronously, recovering them in case of panic. It also provides an error stack aiming to facilitate

Dec 20, 2022
Worker - A Golang library that provides worker pools

Worker A Golang library that provides worker pools. Usage See *_test.go files. T

Apr 15, 2022
Simple application that waits for a given time and attempts and then exits

Wait Simple application that waits for a given time and attempts and then exits. WAIT_HOSTS is a list of hosts to wait for. e.g. WAIT_HOSTS=tcp://app:

Nov 24, 2021