{"id":17714533,"url":"https://github.com/mtumilowicz/go-concurrency-goroutine-workshop","last_synced_at":"2025-03-31T11:09:35.215Z","repository":{"id":246410797,"uuid":"806585047","full_name":"mtumilowicz/go-concurrency-goroutine-workshop","owner":"mtumilowicz","description":"Introduction into CSP based concurrency on the example of golang goroutines.","archived":false,"fork":false,"pushed_at":"2024-10-21T18:44:09.000Z","size":43,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-22T10:24:58.787Z","etag":null,"topics":["communicating-sequential-processes","csp","go","golang","golang-examples","golang-go","goroutine","goroutine-pool","goroutine-safe","goroutines","workshop","workshop-materials"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mtumilowicz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-27T13:30:52.000Z","updated_at":"2024-10-21T18:44:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"04e6876d-cf42-4e4b-806a-30d8854448cd","html_url":"https://github.com/mtumilowicz/go-concurrency-goroutine-workshop","commit_stats":null,"previous_names":["mtumilowicz/go-concurrency-goroutine-workshop"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgo-concurrency-goroutine-workshop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgo-concurrency-goroutine-workshop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgo-concurrency-goroutine-workshop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mtumilowicz%2Fgo-concurrency-goroutine-workshop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mtumilowicz","download_url":"https://codeload.github.com/mtumilowicz/go-concurrency-goroutine-workshop/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246458000,"owners_count":20780677,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["communicating-sequential-processes","csp","go","golang","golang-examples","golang-go","goroutine","goroutine-pool","goroutine-safe","goroutines","workshop","workshop-materials"],"created_at":"2024-10-25T11:15:17.791Z","updated_at":"2025-03-31T11:09:35.199Z","avatar_url":"https://github.com/mtumilowicz.png","language":"Go","readme":"[![Build Status](https://app.travis-ci.com/mtumilowicz/go-concurrency-goroutine-workshop.svg?branch=main)](https://app.travis-ci.com/mtumilowicz/go-concurrency-goroutine-workshop)\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)\n\n# go-concurrency-goroutine-workshop\n\n* references\n    * https://www.oreilly.com/library/view/learning-go/9781492077206/ \n    * https://go.dev/tour/concurrency/5\n    * https://en.wikipedia.org/wiki/Communicating_sequential_processes\n    * https://www.sciencedirect.com/topics/computer-science/communicating-sequential-process\n    * https://slikts.github.io/concurrency-glossary/?id=communicating-sequential-processes-csp\n    * https://medium.com/@arturkulig/communicating-sequential-processes-in-js-intro-e620688b6175\n    * https://dev.to/karanpratapsingh/csp-vs-actor-model-for-concurrency-1cpg\n    * https://aiochan.readthedocs.io/en/latest/csp.html\n    * https://chatgpt.com/\n\n## preface\n* goals of this workshop\n    * introduction to concurrency approach taken by golang\n        * Communicating Sequential Processes (CSP)\n        * how it differs from actor model\n    * understanding of basic components\n        * goroutine\n        * channel and select\n        * context\n    * peek into concurrency primitives\n        * `WaitGroup`s, mutexes, atomics\n* workshop plan\n    1. task1\n        1. execute two requests in parallel (`fetchCustomer`, `fetchProduct`)\n        1. add timeouts than can terminate http requests\n        1. return both customer and product to enable further processing\n    1. task2\n        * encapsulate heavy computation in a function that supports\n            1. contextual timeout\n            1. declarative timeout\n    1. task3\n        * divide and conquer: split array to smaller sums, sum them in goroutines and sum partial results\n\n## prerequisite\n* Communicating Sequential Processes (CSP)\n    * mathematical theory of concurrency based on message passing via channels\n        * combines the sequential thread (threaded state) abstraction with synchronous message passing communication\n            * collection of independent processes with a distinct memory space\n                * example: two processes may run on two cores of the same multiprocessor chip\n            * data is exchanged between processors by the sending and receiving of messages\n    * gradation\n        * processes\n            * group of codes that can be considered as an independent entity\n            * example: function\n        * sequential processes\n            * deterministically equivalent to sequential execution\n            * it is possible to predict what happens next by knowing the current state\n            * disclaimer: it does not mean execution from top to bottom\n                * control statements like while, for, etc., are useful because they disrupt the sequential flow\n        * communicating sequential processes\n            * sequential processes + IO by rendezvous\n                * rendezvous = synchronization mechanism where two processes come together to exchange data directly and simultaneously\n    * vs actor model\n        * actors have identities\n            * processes in CSP are anonymous\n        * actor model: asynchronous + indirect communication\n            * CSP: synchronous + direct communication\n        * actor model: no ordering guarantees across different senders\n            * CSP messages are delivered in the order they were sent\n\n## components\n* goroutine\n    * based CSP\n    * lightweight thread, managed by the Go runtime\n        * Go runtime\n            * set of kernel-level threads, each managing a local run queue (LRQ) of goroutines\n                * number of threads = `GOMAXPROCS`\n                * global run queue (GRQ) for goroutines not assigned yet to a kernel-level thread\n                * work stealing to balance queues\n                    * example: blocking operations\n                        * old thread with its goroutine waiting is descheduled by the OS\n                        * LRQ is moved to other thread (new or from the idle pool)\n            * program starts =\u003e Go runtime creates a number of threads and launches a single goroutine to run program\n    * stack sizes can grow as needed\n    * launched by placing the `go` keyword before a function invocation\n    * any values returned by the function are ignored\n        * goroutines communicate using channels\n    * most of the time has no parameters\n        * captures values from the environment\n        * if variable might change =\u003e pass by parameter\n* channel\n    * are message boxes — stacks of messages with no specified receiver\n    * act as synchronization points\n        * reading and writing to a channel are synchronized operations\n        * makes them safe even if they run in parallel\n    * example\n        ```\n        ch := make(chan int)\n        a := \u003c-ch // read\n        ch \u003c- b // write\n        ```\n    * passing a channel to a function = passing a pointer to the channel\n        * similar to how `map` is implemented\n    * value written to a channel can be read only once\n        * in particular: multiple goroutines reading same channel =\u003e value read by only one of them\n    * convention for passing / assigning\n        * `ch \u003c-chan int` - only reads from the channel\n        * `ch chan\u003c- int` - only writes to the channel\n        * allows the Go compiler to ensure that a channel is only read from or written to by a function\n    * default: unbuffered - only one slot\n        * similar to promise\n            * write =\u003e blocks until empty\n            * read =\u003e blocks until non-empty\n        * buffered: `make(chan int, 10)`\n            * send operation will block only if the buffer is full\n            * use cases\n                * gather data back from a set of goroutines\n                * limit concurrent usage\n                * backpressure\n    * zero value: `nil`\n        * read from a `nil` channel never returns\n        * can't be done inside select statement =\u003e program will hang\n    * `close(ch)`\n        * built-in function\n        * calling twice =\u003e panic\n        * write =\u003e panic\n        * read =\u003e always succeeds\n            * closed channel always immediately returns its zero value\n            * buffered =\u003e remaining values will be returned in order\n        * required only if a goroutine is reading\n            * Go’s runtime can detect channels that are no longer referenced\n    * read from a channel by using a for-range loop: `for v := range ch`\n        * loop continues until the channel is closed or break / return statement is reached\n    * `select`\n        * allows a goroutine to wait on multiple communication operations (reading/writing)\n            * it doesn't specifically allow to read/write to multiple channels simultaneously\n            * lets a goroutine wait until one of the multiple channel operations can proceed\n        * blocks until one of its cases can run\n            * picks randomly from any of its cases that can go forward\n        * prevents acquiring locks in an inconsistent order\n            * select checks whether any of its cases can proceed\n            * every goroutine deadlocked =\u003e runtime kills program\n                * `fatal error: all goroutines are asleep - deadlock!`\n        * for-select loop ~ communicating over a number of channels\n            ```\n            for {\n                select {\n                case msg1 := \u003c-ch1:\n                    fmt.Println(msg1)\n                case msg2 := \u003c-ch2:\n                    fmt.Println(msg2)\n                }\n            }\n            ```\n        * handling closed channels\n            * for-select loop + nil channel\n                ```\n                case v, ok := \u003c-in:\n                    if !ok {\n                        in = nil // the case will never succeed again!\n                    continue\n                ```\n* context\n    * threadlocal doesn’t work in Go\n        * goroutine can be rescheduled to different thread\n    * example: `ctx := context.Background()`\n    * treated as an immutable instance\n        * adding information =\u003e wrapping an existing parent context with a child context\n        * allows to pass information into deeper layers of the code\n            * not the other way around\n        * `Value` method checks whether a value is in a context or any of its parent contexts\n            * linear search\n    * context keys should not collide\n        * pattern\n            ```\n            type productKey struct{}\n            func ContextWithProduct(ctx context.Context, product string) context.Context {\n                return context.WithValue(ctx, productKey{}, product)\n            }\n            func ProductFromContext(ctx context.Context) (string, bool) {\n                product, ok := ctx.Value(productKey{}).(string)\n                return product, ok\n            }\n            ```\n    * can be cancellable\n        * example\n            ```\n            ctx, cancelFunc := context.WithCancel(context.Background())\n            defer cancelFunc() // must be called, otherwise resources leak\n            ```\n        * tells that it’s time to stop processing\n            * `context.Done` method returns a channel of type `struct{}`\n                * empty struct uses no memory\n                * channel is closed when the cancel function is invoked\n                * returns nil if context not cancellable\n            * example\n                ```\n                for {\n                    select {\n                    case // reading other channels\n                    case \u003c-ctx.Done():\n                    }\n                }\n                ```\n            * std HTTP client respects cancellation\n            * use cases\n                * timeouts\n                    ```\n                    ctx, cancel := context.WithTimeout(context.Background(), limit) // reaching the timeout cancels the context\n                    ```\n                * coordinate concurrent goroutines\n                    * example: cancel other goroutines when one of them errored\n        * cause can be specified for the cancellation\n            * example\n                ```\n                ctx, cancelFunc := context.WithCancelCause(context.Background())\n                defer cancelFunc(nil) // creating nil cause\n\n                context.Cause(ctx) // reading cause\n                ```\n            * added in Go 1.20\n    * convention: explicitly passed as the first parameter of a function\n\n## primitives\n* `WaitGroup`\n    * similar to `CountDownLatch` in java\n    * use case\n        * used to wait for a collection of goroutines to finish executing\n        * channel being written by multiple goroutines can be closed only once\n* `Once`\n    * use case\n        * lazy load\n        * call some initialization exactly once\n* mutex\n    * use case\n        * sharing access to a field in a struct\n        * nearly any other case =\u003e use channels\n    * not reentrant\n        * trying to acquire the same lock twice =\u003e deadlock\n    * option: readers–writer mutex\n        * blocks concurrency when writing\n* atomics\n    * sync/atomic package\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fgo-concurrency-goroutine-workshop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmtumilowicz%2Fgo-concurrency-goroutine-workshop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmtumilowicz%2Fgo-concurrency-goroutine-workshop/lists"}