routine

package module
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2022 License: MIT Imports: 8 Imported by: 72

README

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/timandy/routine

Use goid

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

package main

import (
	"fmt"
	"github.com/timandy/routine"
	"time"
)

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

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

curr goid: 1
all goids: [1 18]
each goid: 1 18

Use ThreadLocal

The following code briefly demonstrates ThreadLocal's creation, setting, getting, spreading across coroutines, etc.:

package main

import (
	"fmt"
	"github.com/timandy/routine"
	"time"
)

var threadLocal = routine.NewThreadLocal()
var inheritableThreadLocal = routine.NewInheritableThreadLocal()

func main() {
	threadLocal.Set("hello world")
	inheritableThreadLocal.Set("Hello world2")
	fmt.Println("threadLocal:", threadLocal.Get())
	fmt.Println("inheritableThreadLocal:", inheritableThreadLocal.Get())

	// Other goroutines cannot read the previously assigned "hello world"
	go func() {
		fmt.Println("threadLocal in goroutine:", threadLocal.Get())
		fmt.Println("inheritableThreadLocal in goroutine:", inheritableThreadLocal.Get())
	}()

	// However, a new goroutine can be started via the Go function. All the inheritable variables of the current main goroutine can be passed away automatically.
	routine.Go(func() {
		fmt.Println("threadLocal in goroutine by Go:", threadLocal.Get())
		fmt.Println("inheritableThreadLocal in goroutine by Go:", inheritableThreadLocal.Get())
	})

	time.Sleep(time.Second)
}

The execution result is:

threadLocal: hello world
inheritableThreadLocal: Hello world2
threadLocal in goroutine: <nil>
inheritableThreadLocal in goroutine: <nil>
threadLocal in goroutine by Go: <nil>
inheritableThreadLocal in goroutine by Go: Hello world2

API

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

Goid() 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() []int64

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

In go 1.12 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 using it in high-frequency logic. .

In versions after go 1.13, 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 using it at high frequencies.

ForeachGoid(fun func(goid int64))

Execute the specified function for the goid of all active goroutines in the current process.

The way to get goids is the same as AllGoids() []int64. Since allglock is locked during the whole process, do not execute functions that take a long time, otherwise it will affect the creation of coroutines.

NewThreadLocal() ThreadLocal

Creates a new ThreadLocal instance with a stored default value of nil.

NewThreadLocalWithInitial(supplier Supplier) ThreadLocal

Creates a new ThreadLocal instance with default values stored by calling supplier().

NewInheritableThreadLocal() ThreadLocal

Creates a new ThreadLocal instance with a stored default value of nil. When a new coroutine is started via Go(), GoWait() or GoWaitResult(), the value of the current coroutine is copied to the new coroutine .

NewInheritableThreadLocalWithInitial(supplier Supplier) ThreadLocal

Creates a new ThreadLocal instance with stored default values generated by calling supplier(). When a new coroutine is started via Go(), GoWait() or GoWaitResult(), the value of the current coroutine is copied to the new coroutine .

Go(fun func())

Start a new coroutine and automatically copy all contextual inheritableThreadLocals data of the current coroutine to the new coroutine. Any panic while the child coroutine is executing will be caught and the stack automatically printed.

GoWait(fun func()) Feature

Start a new coroutine and automatically copy all contextual inheritableThreadLocals data of the current coroutine to the new coroutine. You can wait for the sub-coroutine to finish executing through the Feature.Get() method that returns a value. Any panic while the child coroutine is executing will be caught and thrown again when Feature.Get() is called.

GoWaitResult(fun func() Any) Feature

Start a new coroutine and automatically copy all contextual inheritableThreadLocals data of the current coroutine to the new coroutine. You can wait for the sub-coroutine to finish executing and get the return value through the Feature.Get() method of the return value. Any panic while the child coroutine is executing will be caught and thrown again when Feature.Get() is called.

More API Documentation

Garbage Collection

The routine library internally maintains the global globalMap 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 globalMap needs to be cleaned up. It scans and cleans up the context variables cached by dead coroutine in globalMap at regular intervals, to avoid possible hidden dangers of memory leaks.

License

MIT

Thanks

This lib is forked from go-eden/routine. Thank go-eden for his great work!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllGoids

func AllGoids() []int64

AllGoids return all goroutine's goid in the current golang process. It will try load all goid from runtime natively for better performance, and fall over to runtime.Stack, which is very inefficient.

func ForeachGoid added in v1.0.3

func ForeachGoid(fun func(goid int64))

ForeachGoid run a func for each goroutine's goid in the current golang process. It will try load all goid from runtime natively for better performance, and fall over to runtime.Stack, which is very inefficient.

func Go

func Go(fun func())

Go starts a new goroutine, and copy inheritableThreadLocals from current goroutine. This function will auto invoke the fun and print error stack when panic occur in goroutine.

func Goid

func Goid() int64

Goid return the current goroutine's unique id. It will try to get goid by native cgo/asm for better performance, and could parse goid from stack for fail over supporting.

Types

type Any added in v1.0.2

type Any = interface{}

Any equals to interface{}.

type Cloneable added in v1.0.3

type Cloneable interface {
	// Clone create and returns a copy of this object.
	Clone() Any
}

Cloneable interface to support copy itself.

type Feature added in v1.0.2

type Feature interface {
	// Complete notifies the parent coroutine that the task has completed and returns the execution result.
	// This method is called by the child coroutine.
	Complete(result Any)

	// CompleteError notifies the parent coroutine that the task is terminated due to panic and returns stack information.
	// This method is called by the child coroutine.
	CompleteError(error Any)

	// Get the execution result of the sub-coroutine, if there is no result, return nil.
	// If panic is raised during the execution of the sub-coroutine, it will be raised again at this time.
	// this method is called by the parent coroutine.
	Get() Any
}

Feature provide a way to wait for the sub-coroutine to finish executing, get the return value of the sub-coroutine, and catch the sub-coroutine panic.

func GoWait added in v1.0.2

func GoWait(fun func()) Feature

GoWait starts a new goroutine, and copy inheritableThreadLocals from current goroutine. This function return a Feature pointer, so we can wait by Feature.Get method. If panic occur in goroutine, The panic will be trigger again when calling Feature.Get method.

func GoWaitResult added in v1.0.2

func GoWaitResult(fun func() Any) Feature

GoWaitResult starts a new goroutine, and copy inheritableThreadLocals from current goroutine. This function return a Feature pointer, so we can wait and get result by Feature.Get method. If panic occur in goroutine, The panic will be trigger again when calling Feature.Get method.

func NewFeature added in v1.0.2

func NewFeature() Feature

NewFeature Create a new instance.

type StackError added in v1.0.2

type StackError interface {
	// Message data when panic is raised.
	Message() Any

	// StackTrace stack when this instance is created.
	StackTrace() string

	// Error contains Message and StackTrace.
	Error() string
}

StackError an error type contains stack info.

func NewStackError added in v1.0.2

func NewStackError(message Any) StackError

NewStackError create a new instance.

type Supplier added in v1.0.2

type Supplier = func() Any

Supplier provides a function which return Any type result.

type ThreadLocal added in v1.0.2

type ThreadLocal interface {
	// Id returns the global id of instance.
	Id() int

	// Get returns the value in the current goroutine's local threadLocals or inheritableThreadLocals, if it was set before.
	Get() Any

	// Set copy the value into the current goroutine's local threadLocals or inheritableThreadLocals.
	Set(value Any)

	// Remove delete the value from the current goroutine's local threadLocals or inheritableThreadLocals.
	Remove()
}

ThreadLocal provides goroutine-local variables.

func NewInheritableThreadLocal added in v1.0.2

func NewInheritableThreadLocal() ThreadLocal

NewInheritableThreadLocal create and return a new ThreadLocal instance. The initial value is nil. The value can be inherited to sub goroutines witch started by Go, GoWait, GoWaitResult methods.

func NewInheritableThreadLocalWithInitial added in v1.0.2

func NewInheritableThreadLocalWithInitial(supplier Supplier) ThreadLocal

NewInheritableThreadLocalWithInitial create and return a new ThreadLocal instance. The initial value is determined by invoking the supplier method. The value can be inherited to sub goroutines witch started by Go, GoWait, GoWaitResult methods.

func NewThreadLocal added in v1.0.2

func NewThreadLocal() ThreadLocal

NewThreadLocal create and return a new ThreadLocal instance. The initial value is nil.

func NewThreadLocalWithInitial added in v1.0.2

func NewThreadLocalWithInitial(supplier Supplier) ThreadLocal

NewThreadLocalWithInitial create and return a new ThreadLocal instance. The initial value is determined by invoking the supplier method.

Directories

Path Synopsis
g
Package g exposes goroutine struct g to user space.
Package g exposes goroutine struct g to user space.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL