From d28d1d563ebb06fbe0882bf8265622ae62738946 Mon Sep 17 00:00:00 2001 From: nikandfor Date: Sun, 7 Jan 2024 02:48:13 +0100 Subject: [PATCH] benchmark; readme --- README.md | 48 +++++++++++++++--------------------------------- batch4_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 940bdd1..62e1d9c 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,12 @@ This is all without timeouts, additional goroutines, allocations, and channels. ## Usage ``` +// General pattern is +// QueueIn -> Enter -> defer Exit -> Commit/Cancel/return/panic + var sum int -bc := batch.Controller[int]{ +bc := batch.Coordinator[int]{ // Required Commit: func(ctx context.Context) (int, error) { // commit sum @@ -37,18 +40,22 @@ bc := batch.Controller[int]{ for j := 0; j < N; j++ { go func(j int) { - ctx := context.WithValue(ctx, workerID{}, j) // can be obtained in Controller.Commit + ctx := context.WithValue(ctx, workerID{}, j) // can be obtained in Coordinator.Commit + + bc.QueueIn() // let others know we are going to join - b, i := bc.Enter(true) - defer b.Exit() + data := 1 // prepare data - if i == 0 { // we are first in batch, reset it - sum = 0 // or you can do in in the end of commit function + idx := bc.Enter(true) + defer bc.Exit() + + if idx == 0 { // we are first in the batch, reset it + sum = 0 } - sum++ // add work to the batch + sum += data // add data to the batch - res, err := b.Commit(ctx) + res, err := bc.Commit(ctx, false) if err != nil { // works the same as we had independent commit in each goroutine _ = err } @@ -59,31 +66,6 @@ for j := 0; j < N; j++ { } ``` -Lower level API allows queue up in advance, before actually entering batch. -This can be used instead of waiting for timeout for other workers to come. -Instead workers declare itself and now they may be a bit late. - -``` -b := bc.Batch() -defer b.Exit() // should be called with defer to outlive panics - -b.QueueUp() // now we will be waited for. - -// prepare data -x := 3 - -b.Enter(true) // enter syncronized section - -// add data to a common batch -sum += x - -_, _ = b.Commit(ctx) - -// we are still in syncronized section until Exit is called -``` - -`Controller.Enter` is a shortcut for `Controller.Batch, Batch.QueueUp, Batch.Enter`. - Batch is error and panic proof which means the user code can return error or panic in any place, but as soon as all workers left the batch its state is reset. But not the external state, it's callers responsibility to keep it consistent. diff --git a/batch4_test.go b/batch4_test.go index a738a90..58bd76b 100644 --- a/batch4_test.go +++ b/batch4_test.go @@ -167,3 +167,48 @@ func TestCoordinatorAllCases(tb *testing.T) { wg.Wait() } + +func BenchmarkCoordinator(tb *testing.B) { + tb.ReportAllocs() + + ctx := context.Background() + + var sum int + + bc := batch.Coordinator[int]{ + CommitFunc: func(ctx context.Context) (int, error) { + return sum, nil + }, + } + + tb.RunParallel(func(tb *testing.PB) { + for tb.Next() { + func() { + bc.QueueIn() + + // runtime.Gosched() + + idx := bc.Enter(true) + defer bc.Exit() + + // tb.Logf("worker %2d iter %2d enters %2d", j, i, idx) + + if idx == 0 { + sum = 0 + } + + sum += 1 + + res, err := bc.Commit(ctx, false) + if err != nil { + // tb.Errorf("commit: %v", err) + _ = err + } + + // tb.Logf("worker %2d iter %2d res %2d %v", j, i, res, err) + + _ = res + }() + } + }) +}