routine

package module
v1.1.3 Latest Latest
Warning

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

Go to latest
Published: Nov 27, 2023 License: Apache-2.0 Imports: 12 Imported by: 29

README

routine

Build Status Codecov Go Report Card Documentation Release License

中文版

routine encapsulates and provides some easy-to-use, non-competitive, high-performance goroutine context access interfaces, which can help you access coroutine context information more gracefully.

Introduce

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

If you have used other languages such as C++, Java and so on, then you must be familiar with ThreadLocal, but after starting to use Golang, you will be deeply confused and distressed by the lack of convenient functions like ThreadLocal.

Of course, you can choose to use Context, which carries all the context information, appears in the first input parameter of all functions, and then shuttles around your system.

And the core goal of routine is to open up another way: Introduce goroutine local storage to the Golang world.

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():

package main

import (
	"fmt"
	"time"

	"github.com/timandy/routine"
)

func main() {
	goid := routine.Goid()
	fmt.Printf("cur goid: %v\n", goid)
	go func() {
		goid := routine.Goid()
		fmt.Printf("sub goid: %v\n", goid)
	}()

	// Wait for the sub-coroutine to finish executing.
	time.Sleep(time.Second)
}

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

cur goid: 1
sub goid: 6

Use ThreadLocal

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

package main

import (
	"fmt"
	"time"

	"github.com/timandy/routine"
)

var threadLocal = routine.NewThreadLocal[string]()
var inheritableThreadLocal = routine.NewInheritableThreadLocal[string]()

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

	// The child coroutine 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 sub-coroutine can be started via the Go/GoWait/GoWaitResult function, and all inheritable variables of the current coroutine can be passed automatically.
	routine.Go(func() {
		fmt.Println("threadLocal in goroutine by Go:", threadLocal.Get())
		fmt.Println("inheritableThreadLocal in goroutine by Go:", inheritableThreadLocal.Get())
	})

	// You can also create a task via the WrapTask/WrapWaitTask/WrapWaitResultTask function, and all inheritable variables of the current coroutine can be automatically captured.
	task := routine.WrapTask(func() {
		fmt.Println("threadLocal in task by WrapTask:", threadLocal.Get())
		fmt.Println("inheritableThreadLocal in task by WrapTask:", inheritableThreadLocal.Get())
	})
	go task.Run()

	// Wait for the sub-coroutine to finish executing.
	time.Sleep(time.Second)
}

The execution result is:

threadLocal: hello world
inheritableThreadLocal: Hello world2
threadLocal in goroutine:
inheritableThreadLocal in goroutine:
threadLocal in goroutine by Go:
inheritableThreadLocal in goroutine by Go: Hello world2
threadLocal in task by WrapTask:
inheritableThreadLocal in task by WrapTask: 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.

It can be obtained directly through assembly code under 386, amd64, armv6, armv7, arm64, loong64, mips, mipsle, mips64, mips64le, ppc64, ppc64le, riscv64, s390x, wasm architectures. This operation has extremely high performance and the time-consuming is usually only one-fifth of rand.Int().

NewThreadLocal[T any]() ThreadLocal[T]

Create a new ThreadLocal[T] instance with the initial value stored with the default value of type T.

NewThreadLocalWithInitial[T any](supplier Supplier[T]) ThreadLocal[T]

Create a new ThreadLocal[T] instance with the initial value stored as the return value of the method supplier().

NewInheritableThreadLocal[T any]() ThreadLocal[T]

Create a new ThreadLocal[T] instance with the initial value stored with the default value of type T. When a new coroutine is started via Go(), GoWait() or GoWaitResult(), the value of the current coroutine is copied to the new coroutine. When a new task is created via WrapTask(), WrapWaitTask() or WrapWaitResultTask(), the value of the current coroutine is captured to the new task.

NewInheritableThreadLocalWithInitial[T any](supplier Supplier[T]) ThreadLocal[T]

Create a new ThreadLocal[T] instance with the initial value stored as the return value of the method supplier(). When a new coroutine is started via Go(), GoWait() or GoWaitResult(), the value of the current coroutine is copied to the new coroutine. When a new task is created via WrapTask(), WrapWaitTask() or WrapWaitResultTask(), the value of the current coroutine is captured to the new task.

WrapTask(fun Runnable) FutureTask[any]

Create a new task and capture the inheritableThreadLocals from the current goroutine. This function returns a FutureTask instance, but the return task will not run automatically. You can run it in a sub-goroutine or goroutine-pool by FutureTask.Run() method, wait by FutureTask.Get() or FutureTask.GetWithTimeout() method. When the returned task run panic will be caught and error stack will be printed, the panic will be trigger again when calling FutureTask.Get() or FutureTask.GetWithTimeout() method.

WrapWaitTask(fun CancelRunnable) FutureTask[any]

Create a new task and capture the inheritableThreadLocals from the current goroutine. This function returns a FutureTask instance, but the return task will not run automatically. You can run it in a sub-goroutine or goroutine-pool by FutureTask.Run() method, wait by FutureTask.Get() or FutureTask.GetWithTimeout() method. When the returned task run panic will be caught, the panic will be trigger again when calling FutureTask.Get() or FutureTask.GetWithTimeout() method.

WrapWaitResultTask[TResult any](fun CancelCallable[TResult]) FutureTask[TResult]

Create a new task and capture the inheritableThreadLocals from the current goroutine. This function returns a FutureTask instance, but the return task will not run automatically. You can run it in a sub-goroutine or goroutine-pool by FutureTask.Run() method, wait and get result by FutureTask.Get() or FutureTask.GetWithTimeout() method. When the returned task run panic will be caught, the panic will be trigger again when calling FutureTask.Get() or FutureTask.GetWithTimeout() method.

Go(fun Runnable)

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 CancelRunnable) FutureTask[any]

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 FutureTask.Get() or FutureTask.GetWithTimeout() method that returns a value. Any panic while the child coroutine is executing will be caught and thrown again when FutureTask.Get() or FutureTask.GetWithTimeout() is called.

GoWaitResult[TResult any](fun CancelCallable[TResult]) FutureTask[TResult]

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 FutureTask.Get() or FutureTask.GetWithTimeout() method of the return value. Any panic while the child coroutine is executing will be caught and thrown again when FutureTask.Get() or FutureTask.GetWithTimeout() is called.

More API Documentation

Garbage Collection

routine allocates a thread structure for each coroutine, which stores context variable information related to the coroutine.

A pointer to this structure is stored on the g.labels field of the coroutine structure.

When the coroutine finishes executing and exits, g.labels will be set to nil, no longer referencing the thread structure.

The thread structure will be collected at the next GC.

If the data stored in thread is not additionally referenced, these data will be collected together.

Support Grid

darwin linux windows freebsd js
386 386
amd64 amd64
armv6 armv6
armv7 armv7
arm64 arm64
loong64 loong64
mips mips
mipsle mipsle
mips64 mips64
mips64le mips64le
ppc64 ppc64
ppc64le ppc64le
riscv64 riscv64
s390x s390x
wasm wasm
darwin linux windows freebsd js

✅: Supported

Thanks

Thanks to all contributors for their contributions!

License

routine is released under the Apache License 2.0.

Copyright 2021-2023 TimAndy

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Go

func Go(fun Runnable)

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

func Goid

func Goid() int64

Goid return the current goroutine's unique id.

Types

type Callable added in v1.0.7

type Callable[TResult any] func() TResult

Callable provides a function that returns a value of type TResult.

type CancelCallable added in v1.0.9

type CancelCallable[TResult any] func(token CancelToken) TResult

CancelCallable provides a cancellable function that returns a value of type TResult.

type CancelRunnable added in v1.0.9

type CancelRunnable func(token CancelToken)

CancelRunnable provides a cancellable function without return values.

type CancelToken added in v1.0.9

type CancelToken interface {
	// IsCanceled returns true if task was canceled.
	IsCanceled() bool

	// Cancel notifies the waiting coroutine that the task has canceled and returns stack information.
	Cancel()
}

CancelToken propagates notification that operations should be canceled.

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 FutureCallable added in v1.1.2

type FutureCallable[TResult any] func(task FutureTask[TResult]) TResult

FutureCallable provides a future function that returns a value of type TResult.

type FutureTask added in v1.1.2

type FutureTask[TResult any] interface {
	// IsDone returns true if completed in any fashion: normally, exceptionally or via cancellation.
	IsDone() bool

	// IsCanceled returns true if task was canceled.
	IsCanceled() bool

	// IsFailed returns true if completed exceptionally.
	IsFailed() bool

	// Complete notifies the waiting coroutine that the task has completed normally and returns the execution result.
	Complete(result TResult)

	// Cancel notifies the waiting coroutine that the task has canceled and returns stack information.
	Cancel()

	// Fail notifies the waiting coroutine that the task has terminated due to panic and returns stack information.
	Fail(error any)

	// Get return the execution result of the sub-coroutine, if there is no result, return nil.
	// If task is canceled, a panic with cancellation will be raised.
	// If panic is raised during the execution of the sub-coroutine, it will be raised again at this time.
	Get() TResult

	// GetWithTimeout return the execution result of the sub-coroutine, if there is no result, return nil.
	// If task is canceled, a panic with cancellation will be raised.
	// If panic is raised during the execution of the sub-coroutine, it will be raised again at this time.
	// If the deadline is reached, a panic with timeout error will be raised.
	GetWithTimeout(timeout time.Duration) TResult

	// Run execute the task, the method can be called repeatedly, but the task will only execute once.
	Run()
}

FutureTask 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 CancelRunnable) FutureTask[any]

GoWait starts a new goroutine, and copy inheritableThreadLocals from current goroutine. This function will auto invoke the func and return a FutureTask instance, so we can wait by FutureTask.Get or FutureTask.GetWithTimeout method. If panic occur in goroutine, The panic will be trigger again when calling FutureTask.Get or FutureTask.GetWithTimeout method.

func GoWaitResult added in v1.0.2

func GoWaitResult[TResult any](fun CancelCallable[TResult]) FutureTask[TResult]

GoWaitResult starts a new goroutine, and copy inheritableThreadLocals from current goroutine. This function will auto invoke the func and return a FutureTask instance, so we can wait and get result by FutureTask.Get or FutureTask.GetWithTimeout method. If panic occur in goroutine, The panic will be trigger again when calling FutureTask.Get or FutureTask.GetWithTimeout method.

func NewFutureTask added in v1.1.2

func NewFutureTask[TResult any](callable FutureCallable[TResult]) FutureTask[TResult]

NewFutureTask Create a new instance.

func WrapTask added in v1.1.2

func WrapTask(fun Runnable) FutureTask[any]

WrapTask create a new task and capture the inheritableThreadLocals from the current goroutine. This function returns a FutureTask instance, but the return task will not run automatically. You can run it in a sub-goroutine or goroutine-pool by FutureTask.Run method, wait by FutureTask.Get or FutureTask.GetWithTimeout method. When the returned task run panic will be caught and error stack will be printed, the panic will be trigger again when calling FutureTask.Get or FutureTask.GetWithTimeout method.

func WrapWaitResultTask added in v1.1.2

func WrapWaitResultTask[TResult any](fun CancelCallable[TResult]) FutureTask[TResult]

WrapWaitResultTask create a new task and capture the inheritableThreadLocals from the current goroutine. This function returns a FutureTask instance, but the return task will not run automatically. You can run it in a sub-goroutine or goroutine-pool by FutureTask.Run method, wait and get result by FutureTask.Get or FutureTask.GetWithTimeout method. When the returned task run panic will be caught, the panic will be trigger again when calling FutureTask.Get or FutureTask.GetWithTimeout method.

func WrapWaitTask added in v1.1.2

func WrapWaitTask(fun CancelRunnable) FutureTask[any]

WrapWaitTask create a new task and capture the inheritableThreadLocals from the current goroutine. This function returns a FutureTask instance, but the return task will not run automatically. You can run it in a sub-goroutine or goroutine-pool by FutureTask.Run method, wait by FutureTask.Get or FutureTask.GetWithTimeout method. When the returned task run panic will be caught, the panic will be trigger again when calling FutureTask.Get or FutureTask.GetWithTimeout method.

type Runnable added in v1.0.7

type Runnable func()

Runnable provides a function without return values.

type RuntimeError added in v1.0.8

type RuntimeError interface {
	// Goid returns the goid of the coroutine that created the current error.
	Goid() int64

	// Gopc returns the pc of go statement that created the current error coroutine.
	Gopc() uintptr

	// Message returns the detail message string of this error.
	Message() string

	// StackTrace returns an array of stack trace elements, each representing one stack frame.
	StackTrace() []uintptr

	// Cause returns the cause of this error or nil if the cause is nonexistent or unknown.
	Cause() RuntimeError

	// Error returns a short description of this error.
	Error() string
}

RuntimeError runtime error with stack info.

func NewRuntimeError added in v1.0.8

func NewRuntimeError(cause any) RuntimeError

NewRuntimeError create a new RuntimeError instance.

func NewRuntimeErrorWithMessage added in v1.0.8

func NewRuntimeErrorWithMessage(message string) RuntimeError

NewRuntimeErrorWithMessage create a new RuntimeError instance.

func NewRuntimeErrorWithMessageCause added in v1.0.8

func NewRuntimeErrorWithMessageCause(message string, cause any) RuntimeError

NewRuntimeErrorWithMessageCause create a new RuntimeError instance.

type Supplier added in v1.0.2

type Supplier[T any] func() T

Supplier provides a function that returns a value of type T.

type ThreadLocal added in v1.0.2

type ThreadLocal[T any] interface {
	// Get returns the value in the current goroutine's local threadLocals or inheritableThreadLocals, if it was set before.
	Get() T

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

	// 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[T any]() ThreadLocal[T]

NewInheritableThreadLocal create and return a new ThreadLocal instance. The initial value stored with the default value of type T. The value can be inherited to sub goroutines witch started by Go, GoWait, GoWaitResult methods. The value can be captured to FutureTask which created by WrapTask, WrapWaitTask, WrapWaitResultTask methods.

func NewInheritableThreadLocalWithInitial added in v1.0.2

func NewInheritableThreadLocalWithInitial[T any](supplier Supplier[T]) ThreadLocal[T]

NewInheritableThreadLocalWithInitial create and return a new ThreadLocal instance. The initial value stored as the return value of the method supplier. The value can be inherited to sub goroutines witch started by Go, GoWait, GoWaitResult methods. The value can be captured to FutureTask which created by WrapTask, WrapWaitTask, WrapWaitResultTask methods.

func NewThreadLocal added in v1.0.2

func NewThreadLocal[T any]() ThreadLocal[T]

NewThreadLocal create and return a new ThreadLocal instance. The initial value stored with the default value of type T.

func NewThreadLocalWithInitial added in v1.0.2

func NewThreadLocalWithInitial[T any](supplier Supplier[T]) ThreadLocal[T]

NewThreadLocalWithInitial create and return a new ThreadLocal instance. The initial value stored as the return value of the method supplier.

Directories

Path Synopsis
g

Jump to

Keyboard shortcuts

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