{"id":42375671,"url":"https://github.com/wushilin/threads","last_synced_at":"2026-01-27T20:46:55.302Z","repository":{"id":44116130,"uuid":"58518744","full_name":"wushilin/threads","owner":"wushilin","description":null,"archived":false,"fork":false,"pushed_at":"2022-02-17T13:01:42.000Z","size":43,"stargazers_count":4,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-15T04:24:17.365Z","etag":null,"topics":["concurrent","golang","parallel","threadpool","threads"],"latest_commit_sha":null,"homepage":null,"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/wushilin.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}},"created_at":"2016-05-11T06:12:32.000Z","updated_at":"2024-10-25T15:56:29.000Z","dependencies_parsed_at":"2022-09-26T17:51:23.663Z","dependency_job_id":null,"html_url":"https://github.com/wushilin/threads","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/wushilin/threads","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wushilin%2Fthreads","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wushilin%2Fthreads/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wushilin%2Fthreads/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wushilin%2Fthreads/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wushilin","download_url":"https://codeload.github.com/wushilin/threads/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wushilin%2Fthreads/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28821895,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T18:44:20.126Z","status":"ssl_error","status_checked_at":"2026-01-27T18:44:09.161Z","response_time":168,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["concurrent","golang","parallel","threadpool","threads"],"created_at":"2026-01-27T20:46:50.575Z","updated_at":"2026-01-27T20:46:55.286Z","avatar_url":"https://github.com/wushilin.png","language":"Go","readme":"# I have re-written this with Generics, Yay!\nThanks to go generics, the code does not use interface{} now!\n\nHowever, due to Golang generics limitation (methods can't introduce new type parameter), so instead of \n```go\npool.Submit(func() interface{})\n```\nWe now have to use \n```go\nthreads.SubmitTask(pool, func() T)\n```\n\nI personally don't think this is a big deal\n\n\n# Threads\n\nStarting go routine in golang is far too easy, and it is cheap! However, generally it is still a a bad\nidea to allow go routine to grow uncontrolled. Hence sometimes you prefer a thread pool concept just like\njava. Here you have it\n\n## Install\n```go\ngo get github.com/wushilin/threads\n```\n\n## Documentation\n$ godoc -http=\":16666\"\n\nBrowse http://localhost:16666\n\n## Usage\n\n### Thread Pool API\n\n#### Import\n\n```go\nimport \"github.com/wushilin/threads\"\n```\n\n### Creating a thread pool, with 30 executors and max of 1 million pending jobs\n```go\nvar thread_pool *threads.ThreadPool = threads.NewPool(30, 1000000)\n// Note that if pending job is more than 1000000, the new submission (call to Submit) will be blocked\n// until the job queue has some space.\n\n// thread_pool.Start() must be called. Without this, threads won't start processing jobs\n// You now can't submit jobs before pool is started because it may cause dead lock if the buffer is not enough.\nthread_pool.Start()\n\n// After thread_pool is started, there is 30 go routines in background, processing jobs\n\n\n``` \n\n### Submiting a job and gets a Future\n```go\nvar fut future.Future = thread_pool.SubmitTask(thread_poo, func() int {\n  return  1 + 6\n})\n\n// Here, submited func that returns a value. The func will be executed by a backend processor\n// where there is free go routine. The submission returns a *threads.Future, which can be used\n// to retrieve the returned value from the func. \n// e.g. \n// resultInt := fut.GetWait() // \u003c= resultInt will be 7, and type is int. Thanks to genercs in go\n```\n\n### Wait until the future is ready to be retrieve\n```go\nresult := fut.GetWait() // \u003c= result will be 7\nfmt.Printf(\"Result of 1 + 6 is %d\", result)\n// Wait until it is run and result is ready\n\n// or if you prefer no blocking, call returns immediately, but may contain no result\nok, result := fut.GetNow()\nif ok {\n  // result is ready\n  fmt.Println(\"Result of 1 + 6 is\", result) // \u003c= result will be 7\n} else {\n  fmt.Println(\"Result is not ready yet\")\n}\n\n// or if you want to wait for max 3 seconds\nok, result := fut.GetTimeout(3*time.Second)\nif ok {\n  // result is ready\n  fmt.Println(\"Result of 1 + 6 is\", result) // \u003c= result will be 7\n} else {\n  fmt.Println(\"Result is not ready yet\") // \u003c= timed out after 3 seconds\n}\n```\n### Stop accepting new jobs\n```go\n// once shutdown, you can't re-start it back\nthread_pool.Shutdown()\n// Now thread_pool can't submit new jobs. All existing submited jobs will be still processed\n// The future previous returned will still materialize\n\n// Wait until all jobs to complete. Calling Wait() on non-shutdown thread pool will be blocked forever\nthread_pool.Wait() \n// You can't call Wait() before you call Shutdown because it may cause dead lock\n// after this call, all futures should be able to be retrieved without delay\n// You can safely disregard this thread_pool after this call. It is useless anyway\n```\n\n### Getting stats of this pool\n```go\nthread_pool.ActiveCount() // active jobs - being executed right now\nthread_pool.PendingCount() // pending count - not started yet\nthread_pool.CompletedCount() //jobs done - result populated already\n```\n\n### Convenient wrapper to do multiple tasks in parallel\n```go\njobs := make([]func() int, 60)\n//... populate the jobs with actual jobs\n// This will start as many threads as possible to run things in parallel\nvar fg *threads.FutureGroup = threads.ParallelDo(jobs)\n\n// This will start at most 10 threads for parallel processing\nvar fg *threads.FutureGroup = threads.ParallelDoWithLimit(jobs, 10)\n\n// retrieve futures, wait for all and get result!\nvar results []int = fg.WaitAll()\n\n// If you prefer more flexible handling... - you get a copy of the array\nvar []future.Future futures = fg.Futures()\n\n```\n\n# Interesting future concepts\nsee github.com/wushilin/future\n```go\nfut.Then(print) =\u003e print function is called with argument of Future's value, when value become available\n\nfut.Then(print).Then(save) =\u003e multiple then functions can be called\n\nfut := SubmitTask(thread_pool, func() int {\n\treturn 5\n})\nfut2 := future.Chain(fut, func(i int) string {\n\treturn fmt.Sprintf(\"Student #%d\", i)\n}\n\n//fut2 is a future of \"string\" instead of \"int\" now. \n\nfut2.Then(print)\n// print fut2 when it is available\n\nfut3 := future.DelayedFutureOf(\"hello how are you\", 3 * time.Second) =\u003e fut3 is available after 3 seconds\n```\n\n# Future Group now supports\n```\nFutureGroup.Count() // Count the number of futures in the group\nFutureGroup.Futures() // Get a copy of futures (not the underlying future directly)\nFutureGroup.ReadyCount() // Check how many of futures are ready\nFutureGroup.IsAllReady() // Test if all results are present (non-blocking)\nFutureGroup.ThreadPool() // returns original thread pool that produced the future group. You may want to call its Wait() methods (but usually not necessary)\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwushilin%2Fthreads","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwushilin%2Fthreads","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwushilin%2Fthreads/lists"}