Skip to content

Commit

Permalink
Introduced Future
Browse files Browse the repository at this point in the history
  • Loading branch information
wushilin committed Feb 12, 2022
1 parent 19a1092 commit 0e78c7e
Showing 1 changed file with 27 additions and 31 deletions.
58 changes: 27 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -34,33 +34,35 @@ 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


```

### 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
})

// Here, submited func that returns a value. The func will be executed by a backend processor
// 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
Expand All @@ -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
Expand All @@ -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
```
Expand All @@ -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)
Expand All @@ -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
```
Expand All @@ -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
```

0 comments on commit 0e78c7e

Please sign in to comment.