Go Concepts - Runtime

From NovaOrdis Knowledge Base
Revision as of 20:58, 1 September 2023 by Ovidiu (talk | contribs)
Jump to navigation Jump to search

TODO

Merge int Go Development and Execution Environment

Environment Variables

GOPATH

GOPATH is used by the compiler to locate source files and package objects for the packages listed by the import statements in source files being compiled.

It must contain absolute paths.

GOPATH content lists directories on the local file system. GOPATH may contain multiple directories. On UNIX, the value is a colon-separated string. On Windows, the value is a semicolon-separated string. GOPATH must be set every time we need to get and build packages outside the standard Go tree.

The compiler loops over the values listed in GOPATH, in order, appends /src/<package-path-string-literal> to them, as declared in the import statement, and looks into the directories whose name are thus generated for source files that belong to the required packages. This is why it is important that the package and the directory containing the package sources have the same name: if they don't, the compilation fails to find the source file.

Each directory listed in GOPATH must have a prescribed structure:

  • The src directory holds source code. The path below src determines the import path or executable name.
  • The pkg directory holds installed package objects. As in the Go tree, each target operating system and architecture pair has its own subdirectory of pkg: pkg/GOOS_GOARCH.

If DIR is a directory listed in the GOPATH, a package with source in DIR/src/x/y can be imported as "x/y" and has its compiled form installed to "DIR/pkg/GOOS_GOARCH/x/y.a".

  • The bin directory holds compiled commands. Each command is named for its source directory, but only the final element, not the entire path. That is, the command with source in DIR/src/x/blah is installed into DIR/bin/blah, not DIR/bin/x/blah. The "x/" prefix is stripped so that you can add DIR/bin to your PATH to get at the installed commands.

Relative Order

Order in which root directories are listed in GOPATH matters. If two directories contain packages with the same name, the compiler will stop searching once it finds the first package that satisfies the import statement. The compiler first look into Go installation directory, then into the directories listed in GOPATH. The behavior corresponding to the package whose root directory exists in the Go installation, and then is listed first in the GOPATH list is used.

"internal" directories

Code in or below a directory named "internal" is importable only by code in the directory tree rooted at the parent of "internal". For more details see https://golang.org/s/go14internal.

Vendor directories

Vendoring

In-line Documentation

go help gopath

GOBIN

If the GOBIN environment variable is set, commands are installed to the directory it names instead of DIR/bin. GOBIN must be an absolute path.

GOROOT

The Go runtime installation directory. The compiler looks for packages that are imported at location referenced by the GOROOT and GOPATH variables.

GOROOT must be set at installation, Go runtime expects to find the variable in the environment, unless the runtime is installed in /usr/local/go.

Executables vs. Libraries

Executables are native code programs that can be run directly from command line.

Libraries are collection of native code that can be used by other programs.

Compiling an Executable

According to the specifications (https://golang.org/ref/spec#Program_execution), a complete program is created by linking a single, unimported package called the main package with all the package it imports, transitively. The main package must be named "main". The main package must declare a function named main() that takes no arguments and returns no value. The main() function is the entry point in the program. If the "main" package does not contain a main() function, the build tool won't produce an executable:

runtime.main: call to external function main.main
runtime.main: main.main: not defined
runtime.main: undefined: main.main

The program execution begins by initializing the main package and invoking the main() function. Then the function invocation returns, the program exists. It does not wait for other (non-main) goroutines to complete.

Note that the name of the source file that contains the main() function does NOT have to be "main.go". It could be any legal file name. The executable will be created under the name of the file that contains the main() function.

The simplest possible executable named example can be created as follows:

Declare an example.go that defines the "main" package and contains the main() function:

package main

import "fmt"

func main() {
    fmt.Println("I am example")
}

Build the executable:

go build ./example.go

The compiler will create an example executable.

Runtime Scheduler

The Go runtime schedulers that manages all goroutines that are created and need processor time. It binds operating system threads to logic processors, which, in turn, execute goroutines. Each logical process is individually bound to a single operating system thread.

As goroutines are created, they are placed in the scheduler's global run queue. From there, they are added to a logical processor's run queue and executed. Depending on the scheduling algorithm, a running goroutine can be stopped and rescheduled at any time.

When a goroutine makes a blocking system call, the scheduler will detach the thread from the processor and create a new thread to service that processor.

When a goroutine makes a network I/O call, the goroutine is detached from the logical processor and moved to the runtime network poller. Once the poller indicates a read or write operation is ready, the goroutine is assigned back to a logical processor to handle the operation.

SetMaxThreads

The Go runtime limits each program to a maximum 10,000 threads by default. This value can be changed by setting SetMaxThreads in runtime/debug package.