lock free algorithms for kotlin coroutines
play

Lock-free algorithms for Kotlin coroutines It is all about - PowerPoint PPT Presentation

Lock-free algorithms for Kotlin coroutines It is all about scalability Presented at SPTCC 2017 /Roman Elizarov @ JetBrains Speaker: Roman Elizarov 16+ years experience Previously developed high-perf trading software @ Devexperts


  1. Senders wait More Incoming senders receivers Sender #1 Sender #2 Sender #3 H T Receiver removes Sender inserts last if it first if it is a sender is not a receiver node node

  2. Receivers wait More Incoming receivers senders Receiver #1 Receiver #2 Receiver #3 H T Sender removes Receiver inserts last if first if it is a receiver it is not a sender node node

  3. Send function sketch fun send(element: T) { 1 while ( true ) { // try to add sender, unless prev is receiver 2 if (enqueueSend(element)) break // try to remove first receiver 3 val receiver = removeFirstReceiver() if (receiver != null ) { 4 receiver.resume(element) // resume receiver break } } }

  4. Channel use-case recap • Uses insert/remove ops conditional on tail/head node • Can abort (cancel) wait to receive/send at any time by using remove • Full removal -- no garbage is left • Pretty efficient in practice • One item lists – one “garbage” object

  5. Multi-word compare and swap (CASN) Build even bigger atomic operations

  6. Use-case: select expression val channel1 = Channel<Int>() val channel2 = Channel<Int>() select { channel1. onReceive { e -> ... } channel2. onReceive { e -> ... } }

  7. Impl summary: register (1) 1. Not selected Select 2. Selected status: NS Channel1 Channel2 Queue Queue

  8. Impl summary: register (2) Select Add node to channel1 queue if status: NS not selected (NS) yet Channel1 Channel2 Queue Queue N1

  9. Impl summary: register (3) Select Add node to channel2 queue if status: NS not selected (NS) yet Channel1 Channel2 Queue Queue N1 N2

  10. Impl summary: wait Select status: NS Channel1 Channel2 Queue Queue N1 N2

  11. Impl summary: select (resume) Select Make selected and remove node status: S from queue Channel1 Channel2 Queue Queue N1

  12. Impl summary: clean up rest Select Remove non-selected waiters status: S from queue Channel1 Channel2 Queue Queue

  13. Double-Compare Single-Swap (DCSS) Building block for CASN

  14. DCSS spec in pseudo-code A B fun <A,B> dcss( 1 a: Ref<A>, expectA: A, updateA: A, b: Ref<B>, expectB: B) = 2 atomic { 3 if (a. value == expectA && b. value == expectB) { 4 a. value = updateA } }

  15. DCSS: init descriptor expectA A B expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB)

  16. DCSS: prepare expectA A B expectB CAS ptr to descriptor if a. value == expectA updateA DCSS Descriptor (a, expectA, updateA, b, expectB)

  17. DCSS: read b.value expectA A B expectB CAS ptr to descriptor if a. value == expectA updateA DCSS Descriptor (a, expectA, updateA, b, expectB)

  18. DCSS: complete (when success) expectA A B expectB CAS to updated value if a still points to descriptor updateA DCSS Descriptor (a, expectA, updateA, b, expectB)

  19. DCSS: complete (alternative) expectA A B !expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB)

  20. DCSS: complete (when fail) expectA A B !expectB CAS to original value if a still points to descriptor updateA DCSS Descriptor (a, expectA, updateA, b, expectB)

  21. DCSS: States Any other thread encountering descriptor helps complete 1 2 3 Init prep ok success A: desc A: updateA A: ??? A was expectA B was expectB (desc created) prep fail fail 4 5 Originator cannot A: ??? A: expectA learn what was the A was !expectA B was !expectB outcome Lock-free algorithm without loops! one tread

  22. Caveats • A & B locations must be totally ordered • or risk stack-overflow while helping • One way to look at it: Restricted DCSS (RDCSS)

  23. DCSS Mod: learn outcome A B fun <A,B> dcssMod( a: Ref<A>, expectA: A, updateA: A, b: Ref<B>, expectB: B): Boolean = atomic { if (a. value == expectA && b. value == expectB) { a. value = updateA true } else false }

  24. DCSS Mod: init descriptor expectA A B expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB) Outcome: UNDECIDED Consensus

  25. DCSS Mod: prepare expectA A B expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB) Outcome: UNDECIDED

  26. DCSS Mod: read b.value expectA A B expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB) Outcome: UNDECIDED

  27. DCSS Mod: reach consensus expectA A B expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB) Outcome: SUCCESS CAS(UNDECIDED, DECISION)

  28. DCSS Mod: complete expectA A B expectB updateA DCSS Descriptor (a, expectA, updateA, b, expectB) Outcome: SUCCESS

  29. DCSS Mod: States 1 2 3 Init A: desc A: desc prep ok success A: ??? Outcome: UND Outcome: SUCC Outcome: UND A was expectA B was expectB (desc created) prep fail fail 4 5 6 A: updateA A: ??? A: desc Outcome: FAIL Outcome: FAIL 7 A was !expectA A: expectA Still no loops! one tread

  30. Compare-And-Swap N-words (CASN) The ultimate atomic update

  31. CASN spec in pseudo-code For two words, for simplicity A B fun <A,B> cas2( 1 a: Ref<A>, expectA: A, updateA: A, b: Ref<B>, expectB: B, updateB: B): Boolean = 2 atomic { 3 if (a. value == expectA && b. value == expectB) { a. value = updateA 4 b. value = updateB true } else 5 false }

Recommend


More recommend