multithreading - Algorithm to run code with no more than one concurrent thread per unique id -


i have go web application needs execute given section of code in 1 goroutine per unique id. scenario have requests coming various ids represent sort of transaction. subset of operations on these needs guaranteed run "one @ at time" given id (and other competing requests should block until prior 1 working on/for id done).

i can think of few ways book keeping seems tricky - need keep global mutex lock access map of concurrent requests happening , use mutex or counter there, , make sure doesn't deadlock, , garbage collect (or reference count) old request entries. can this, sounds error prone.

is there pattern or in standard library can used effect in case? didn't see obvious.

edit: 1 thing think confusing in explanation above use of word "transaction". in case each of these not need explicit close - it's identifier associate multiple operations with. since don't have explicit "close" or "end" concept these, might receive 3 requests within same second , each operation takes 2 seconds - , need serialize because running them concurrently wreak havoc; might request week later same id , referring same set of operations (the id pk on table in database).

need keep global mutex lock access map of concurrent requests happening , use mutex or counter there, , make sure doesn't deadlock, , garbage collect (or reference count) old request entries

that seems overly complicated. here how it:

  • all map stuff should handled 1 thread (your dispatcher) don't have deal locking. assumes work time greater dispatch time. dispatcher tracks channel , counter per id (in map, obviously).
  • the complication how handle race of "goroutine thinks it's done working on id" vs "dispatcher found more work". answer worker requests cleaned up, dispatcher decides if cleanup request possible or not.

so here how code work:

1) dispatch process reads single input channel. gets 2 types of requests: "new work" (from outside), , "done work" (from worker). both requests include id.

2) dispatcher gets "new work" message: lookup in map id. if find channel + count, send work down channel , increment count. (*) if find nothing, create new channel + count in map, send work down channel (also increment count), create worker (go-routine) reading on channel.

3) worker goroutine pull "new work" channel , work. when done, send "done work" request dispatcher.

4) dispatcher gets "done work" message. lookup in map , find channel + counter. decrement counter. if it's zero, send "quit" message worker, , delete entry in map.

5) if worker goroutine gets "quit" message (instead of work message), exits. (note there tiny race 2nd worker on id created while old 1 exiting. old 1 processing quit message, doesn't matter. old worker clean himself up, including old channel.)

if requests slow enough, there 1 entry in map @ time. other extreme if requests same id fast enough, channel id stay active (just counter go , down).

(*) note: if make channels 5 deep, , 6 messages queued up, dispatcher stall. think can expand channel depth in case, i'm not sure.


Comments

Popular posts from this blog

javascript - Karma not able to start PhantomJS on Windows - Error: spawn UNKNOWN -

Nuget pack csproj using nuspec -

c# - Display ASPX Popup control in RowDeleteing Event (ASPX Gridview) -