From 0e78c7e6aba9b6a16dc7e3f6e515749a71013347 Mon Sep 17 00:00:00 2001 From: Shilin Wu Date: Sat, 12 Feb 2022 15:51:40 +0800 Subject: [PATCH] Introduced Future --- README.md | 58 ++++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 7aa6bcb..7145114 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# I will rewrite this with Generics when Go1.18 is realeased. Stay tuned! +# I have re-written this with Generics, Yay! # Threads @@ -34,7 +34,9 @@ var thread_pool *threads.ThreadPool = threads.NewPool(30, 1000000) // until the job queue has some space. // thread_pool.Start() must be called. Without this, threads won't start processing jobs +// You now can't submit jobs before pool is started because it may cause dead lock if the buffer is not enough. thread_pool.Start() + // After thread_pool is started, there is 30 go routines in background, processing jobs @@ -42,7 +44,7 @@ thread_pool.Start() ### Submiting a job and gets a Future ```go -var fut *threads.Future = thread_pool.Submit(func() interface{} { +var fut future.Future = thread_pool.SubmitTask(thread_poo, func() int { return 1 + 6 }) @@ -50,17 +52,17 @@ var fut *threads.Future = thread_pool.Submit(func() interface{} { // where there is free go routine. The submission returns a *threads.Future, which can be used // to retrieve the returned value from the func. // e.g. -// resultInt := fut.GetWait().(int) // <= resultInt will be 7 +// resultInt := fut.GetWait() // <= resultInt will be 7, and type is int. Thanks to genercs in go ``` ### Wait until the future is ready to be retrieve ```go -result := fut.GetWait().(int) // <= result will be 7 -fmt.Println("Result of 1 + 6 is", result) +result := fut.GetWait() // <= result will be 7 +fmt.Printf("Result of 1 + 6 is %d", result) // Wait until it is run and result is ready // or if you prefer no blocking, call returns immediately, but may contain no result -ok, result := fut.GetNoWait() +ok, result := fut.GetNow() if ok { // result is ready fmt.Println("Result of 1 + 6 is", result) // <= result will be 7 @@ -69,7 +71,7 @@ if ok { } // or if you want to wait for max 3 seconds -ok, result := fut.GetWaitTimeout(3*time.Second) +ok, result := fut.GetTimeout(3*time.Second) if ok { // result is ready fmt.Println("Result of 1 + 6 is", result) // <= result will be 7 @@ -86,6 +88,7 @@ thread_pool.Shutdown() // Wait until all jobs to complete. Calling Wait() on non-shutdown thread pool will be blocked forever thread_pool.Wait() +// You can't call Wait() before you call Shutdown because it may cause dead lock // after this call, all futures should be able to be retrieved without delay // You can safely disregard this thread_pool after this call. It is useless anyway ``` @@ -99,7 +102,7 @@ thread_pool.CompletedCount() //jobs done - result populated already ### Convenient wrapper to do multiple tasks in parallel ```go -jobs := make([]func() interface{}, 60) +jobs := make([]func() int, 60) //... populate the jobs with actual jobs // This will start as many threads as possible to run things in parallel var fg *threads.FutureGroup = threads.ParallelDo(jobs) @@ -111,33 +114,31 @@ var fg *threads.FutureGroup = threads.ParallelDoWithLimit(jobs, 10) var results[]interface{} = fg.WaitAll() // If you prefer more flexible handling... - you get a copy of the array -var []*threads.Future futures = fg.Futures() +var []future.Future futures = fg.Futures() ``` -# Chain futures, to get futures from futures +# Interesting future concepts +see github.com/wushilin/future +```go +fut.Then(print) => print function is called with argument of Future's value, when value become available -``` -func adder(i interface{}) interface{} { - return i.(int) + 1 -} +fut.Then(print).Then(save) => multiple then functions can be called -func sleeper() interface{} { - time.Sleep(1 * time.Second) - return 5 +fut := SubmitTask(thread_pool, func() int { + return 5 +}) +fut2 := Chain(fut, func(i int) string { + return fmt.Sprintf("Student #%d", i) } -func print_value(i interface{}) { - fmt.Println(i) -} +//fut2 is a future of "string" instead of "int" now. -future1 := FutureOf(sleeper).ThenMap(adder) // Non blocking, gets the future immediately: future1 materialize when sleeper return, and final value will be 6 -//(sleeper returned value will be then added 1) -future1.Then(print_value) // Non blocking, print_value is immediately run after future1 is materialized -``` +fut2.Then(print) +// print fut2 when it is available -# Change FutureGroup from struct to pointer, to save possible large array copy (go default uses pass by value) -All code that was using FutureGroup, now should use *FutureGroup +fut3 := future.DelayedFutureOf("hello how are you", 3 * time.Second) => fut3 is available after 3 seconds +``` # Future Group now supports ``` @@ -147,8 +148,3 @@ FutureGroup.ReadyCount() // Check how many of futures are ready FutureGroup.IsAllReady() // Test if all results are present (non-blocking) FutureGroup.ThreadPool() // returns original thread pool that produced the future group. You may want to call its Wait() methods (but usually not necessary) ``` -# Added Instantly method - -``` -threads.InstantFuture(5) => Get a Future that materializes instantly with value 5 -```