@@ -9,13 +9,13 @@ import (
99)
1010
1111// AsyncFunc is a function interface this asyncTask accepts.
12- type AsyncFunc [T any ] func (context.Context ) (* T , error )
12+ type AsyncFunc [T any ] func (context.Context ) (T , error )
1313
1414// ActionToFunc convert a Action to Func (C# term), to satisfy the AsyncFunc interface.
1515// - Action is function that runs without return anything
1616// - Func is function that runs and return something
17- func ActionToFunc (action func (context.Context ) error ) func (context.Context ) (* interface {}, error ) {
18- return func (ctx context.Context ) (* interface {}, error ) {
17+ func ActionToFunc (action func (context.Context ) error ) func (context.Context ) (interface {}, error ) {
18+ return func (ctx context.Context ) (interface {}, error ) {
1919 return nil , action (ctx )
2020 }
2121}
@@ -24,25 +24,25 @@ func ActionToFunc(action func(context.Context) error) func(context.Context) (*in
2424// which you can use to wait, cancel, get the result.
2525type Task [T any ] struct {
2626 state State
27- result * T
27+ result T
2828 err error
2929 cancelFunc context.CancelFunc
3030 waitGroup * sync.WaitGroup
31- mutex * sync.Mutex
31+ mutex * sync.RWMutex
3232}
3333
3434// State return state of the task.
3535func (t * Task [T ]) State () State {
36- t .mutex .Lock ()
37- defer t .mutex .Unlock ()
36+ t .mutex .RLock ()
37+ defer t .mutex .RUnlock ()
3838 return t .state
3939}
4040
4141// Cancel the task by cancel the context.
4242// !! this rely on the task function to check context cancellation and proper context handling.
4343func (t * Task [T ]) Cancel () bool {
4444 if ! t .finished () {
45- t .finish (StateCanceled , nil , ErrCanceled )
45+ t .finish (StateCanceled , * new ( T ) , ErrCanceled )
4646 return true
4747 }
4848
@@ -74,7 +74,7 @@ func (t *Task[T]) Wait(ctx context.Context) error {
7474
7575// WaitWithTimeout block current thread/routine until task finished or failed, or exceed the duration specified.
7676// timeout only stop waiting, taks will remain running.
77- func (t * Task [T ]) WaitWithTimeout (ctx context.Context , timeout time.Duration ) (* T , error ) {
77+ func (t * Task [T ]) WaitWithTimeout (ctx context.Context , timeout time.Duration ) (T , error ) {
7878 // return immediately if task already in terminal state.
7979 if t .finished () {
8080 return t .result , t .err
@@ -86,11 +86,10 @@ func (t *Task[T]) WaitWithTimeout(ctx context.Context, timeout time.Duration) (*
8686 return t .Result (ctx )
8787}
8888
89- func (t * Task [T ]) Result (ctx context.Context ) (* T , error ) {
89+ func (t * Task [T ]) Result (ctx context.Context ) (T , error ) {
9090 err := t .Wait (ctx )
9191 if err != nil {
92- var result T
93- return & result , err
92+ return * new (T ), err
9493 }
9594
9695 return t .result , t .err
@@ -102,11 +101,11 @@ func Start[T any](ctx context.Context, task AsyncFunc[T]) *Task[T] {
102101 ctx , cancel := context .WithCancel (ctx )
103102 wg := & sync.WaitGroup {}
104103 wg .Add (1 )
105- mutex := & sync.Mutex {}
104+ mutex := & sync.RWMutex {}
106105
107106 record := & Task [T ]{
108107 state : StateRunning ,
109- result : nil ,
108+ result : * new ( T ) ,
110109 cancelFunc : cancel ,
111110 waitGroup : wg ,
112111 mutex : mutex ,
@@ -118,24 +117,24 @@ func Start[T any](ctx context.Context, task AsyncFunc[T]) *Task[T] {
118117}
119118
120119// NewCompletedTask returns a Completed task, with result=nil, error=nil
121- func NewCompletedTask [T any ](value * T ) * Task [T ] {
120+ func NewCompletedTask [T any ](value T ) * Task [T ] {
122121 return & Task [T ]{
123122 state : StateCompleted ,
124123 result : value ,
125124 err : nil ,
126125 // nil cancelFunc and waitGroup should be protected with IsTerminalState()
127126 cancelFunc : nil ,
128127 waitGroup : nil ,
129- mutex : & sync.Mutex {},
128+ mutex : & sync.RWMutex {},
130129 }
131130}
132131
133- func runAndTrackGenericTask [T any ](ctx context.Context , record * Task [T ], task func (ctx context.Context ) (* T , error )) {
132+ func runAndTrackGenericTask [T any ](ctx context.Context , record * Task [T ], task func (ctx context.Context ) (T , error )) {
134133 defer record .waitGroup .Done ()
135134 defer func () {
136135 if r := recover (); r != nil {
137136 err := fmt .Errorf ("panic cought: %v, stackTrace: %s, %w" , r , debug .Stack (), ErrPanic )
138- record .finish (StateFailed , nil , err )
137+ record .finish (StateFailed , * new ( T ) , err )
139138 }
140139 }()
141140
@@ -150,7 +149,7 @@ func runAndTrackGenericTask[T any](ctx context.Context, record *Task[T], task fu
150149 record .finish (StateFailed , result , err )
151150}
152151
153- func (t * Task [T ]) finish (state State , result * T , err error ) {
152+ func (t * Task [T ]) finish (state State , result T , err error ) {
154153 // only update state and result if not yet canceled
155154 t .mutex .Lock ()
156155 defer t .mutex .Unlock ()
@@ -163,7 +162,7 @@ func (t *Task[T]) finish(state State, result *T, err error) {
163162}
164163
165164func (t * Task [T ]) finished () bool {
166- t .mutex .Lock ()
167- defer t .mutex .Unlock ()
165+ t .mutex .RLock ()
166+ defer t .mutex .RUnlock ()
168167 return t .state .IsTerminalState ()
169168}
0 commit comments