June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
37
Task/Atomic-updates/Common-Lisp/atomic-updates-1.lisp
Normal file
37
Task/Atomic-updates/Common-Lisp/atomic-updates-1.lisp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
(ql:quickload '(:alexandria :stmx :bordeaux-threads))
|
||||
|
||||
(defpackage :atomic-updates
|
||||
(:use :cl))
|
||||
|
||||
(in-package :atomic-updates)
|
||||
|
||||
(defvar *buckets* nil)
|
||||
(defvar *running* nil)
|
||||
|
||||
(defun distribute (ratio a b)
|
||||
"Atomically redistribute the values of buckets A and B by RATIO."
|
||||
(stmx:atomic
|
||||
(let* ((sum (+ (stmx:$ a) (stmx:$ b)))
|
||||
(a2 (truncate (* ratio sum))))
|
||||
(setf (stmx:$ a) a2)
|
||||
(setf (stmx:$ b) (- sum a2)))))
|
||||
|
||||
(defun runner (ratio-func)
|
||||
"Continously distribute to two different elements in *BUCKETS* with the
|
||||
value returned from RATIO-FUNC."
|
||||
(loop while *running*
|
||||
do (let ((a (alexandria:random-elt *buckets*))
|
||||
(b (alexandria:random-elt *buckets*)))
|
||||
(unless (eq a b)
|
||||
(distribute (funcall ratio-func) a b)))))
|
||||
|
||||
(defun print-buckets ()
|
||||
"Atomically get the bucket values and print out their metrics."
|
||||
(let ((buckets (stmx:atomic (map 'vector 'stmx:$ *buckets*))))
|
||||
(format t "Buckets: ~a~%Sum: ~a~%" buckets (reduce '+ buckets))))
|
||||
|
||||
(defun scenario ()
|
||||
(setf *buckets* (coerce (loop repeat 20 collect (stmx:tvar 10)) 'vector))
|
||||
(setf *running* t)
|
||||
(bt:make-thread (lambda () (runner (constantly 0.5))))
|
||||
(bt:make-thread (lambda () (runner (lambda () (random 1.0))))))
|
||||
10
Task/Atomic-updates/Common-Lisp/atomic-updates-2.lisp
Normal file
10
Task/Atomic-updates/Common-Lisp/atomic-updates-2.lisp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
ATOMIC-UPDATES> (scenario)
|
||||
#<SB-THREAD:THREAD "Anonymous thread" RUNNING {10058441D3}>
|
||||
ATOMIC-UPDATES> (loop repeat 3 do (print-buckets) (sleep 1))
|
||||
Buckets: #(8 4 12 17 12 10 5 10 9 10 4 11 4 15 16 20 11 8 4 10)
|
||||
Sum: 200
|
||||
Buckets: #(2 12 24 7 8 3 13 6 8 31 0 9 7 11 12 8 8 12 15 4)
|
||||
Sum: 200
|
||||
Buckets: #(1 2 3 3 2 8 33 23 0 8 4 11 24 2 3 5 32 8 2 26)
|
||||
Sum: 200
|
||||
NIL
|
||||
60
Task/Atomic-updates/Julia/atomic-updates.julia
Normal file
60
Task/Atomic-updates/Julia/atomic-updates.julia
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using StatsBase
|
||||
|
||||
function runall()
|
||||
nbuckets = 16
|
||||
unfinish = true
|
||||
spinner = ReentrantLock()
|
||||
buckets = rand(1:99, nbuckets)
|
||||
totaltrans = 0
|
||||
|
||||
bucketsum() = sum(buckets)
|
||||
smallpause() = sleep(rand() / 2000)
|
||||
picktwo() = (samplepair(nbuckets)...)
|
||||
function equalizer()
|
||||
while unfinish
|
||||
smallpause()
|
||||
if trylock(spinner)
|
||||
i, j = picktwo()
|
||||
sm = buckets[i] + buckets[j]
|
||||
m = fld(sm + 1, 2)
|
||||
buckets[i], buckets[j] = m, sm - m
|
||||
totaltrans += 1
|
||||
unlock(spinner)
|
||||
end
|
||||
end
|
||||
end
|
||||
function redistributor()
|
||||
while unfinish
|
||||
smallpause()
|
||||
if trylock(spinner)
|
||||
i, j = picktwo()
|
||||
sm = buckets[i] + buckets[j]
|
||||
buckets[i] = rand(0:sm)
|
||||
buckets[j] = sm - buckets[i]
|
||||
totaltrans += 1
|
||||
unlock(spinner)
|
||||
end
|
||||
end
|
||||
end
|
||||
function accountant()
|
||||
count = 0
|
||||
while count < 16
|
||||
smallpause()
|
||||
if trylock(spinner)
|
||||
println("Current state of buckets: $buckets. Total in buckets: $(bucketsum())")
|
||||
unlock(spinner)
|
||||
count += 1
|
||||
sleep(1)
|
||||
end
|
||||
end
|
||||
unfinish = false
|
||||
end
|
||||
t = time()
|
||||
@async equalizer()
|
||||
@async redistributor()
|
||||
@async accountant()
|
||||
while unfinish sleep(0.25) end
|
||||
println("Total transactions: $totaltrans ($(round(Int, totaltrans / (time() - t))) unlocks per second).")
|
||||
end
|
||||
|
||||
runall()
|
||||
84
Task/Atomic-updates/Kotlin/atomic-updates.kotlin
Normal file
84
Task/Atomic-updates/Kotlin/atomic-updates.kotlin
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// version 1.2.0
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
const val NUM_BUCKETS = 10
|
||||
|
||||
class Buckets(data: IntArray) {
|
||||
private val data = data.copyOf()
|
||||
|
||||
operator fun get(index: Int) = synchronized(data) { data[index] }
|
||||
|
||||
fun transfer(srcIndex: Int, dstIndex: Int, amount: Int): Int {
|
||||
if (amount < 0) {
|
||||
throw IllegalArgumentException("Negative amount: $amount")
|
||||
}
|
||||
if (amount == 0) return 0
|
||||
synchronized(data) {
|
||||
var a = amount
|
||||
if (data[srcIndex] - a < 0) a = data[srcIndex]
|
||||
if (data[dstIndex] + a < 0) a = Int.MAX_VALUE - data[dstIndex]
|
||||
if (a < 0) throw IllegalStateException()
|
||||
data[srcIndex] -= a
|
||||
data[dstIndex] += a
|
||||
return a
|
||||
}
|
||||
}
|
||||
|
||||
val buckets get() = synchronized(data) { data.copyOf() }
|
||||
|
||||
fun transferRandomAmount() {
|
||||
val rnd = ThreadLocalRandom.current()
|
||||
while (true) {
|
||||
val srcIndex = rnd.nextInt(NUM_BUCKETS)
|
||||
val dstIndex = rnd.nextInt(NUM_BUCKETS)
|
||||
val amount = rnd.nextInt() and Int.MAX_VALUE
|
||||
transfer(srcIndex, dstIndex, amount)
|
||||
}
|
||||
}
|
||||
|
||||
fun equalize() {
|
||||
val rnd = ThreadLocalRandom.current()
|
||||
while (true) {
|
||||
val srcIndex = rnd.nextInt(NUM_BUCKETS)
|
||||
val dstIndex = rnd.nextInt(NUM_BUCKETS)
|
||||
val amount = (this[srcIndex] - this[dstIndex]) / 2
|
||||
if (amount >= 0) transfer(srcIndex, dstIndex, amount)
|
||||
}
|
||||
}
|
||||
|
||||
fun print() {
|
||||
while (true) {
|
||||
val nextPrintTime = System.currentTimeMillis() + 3000
|
||||
while (true) {
|
||||
val now = System.currentTimeMillis()
|
||||
if (now >= nextPrintTime) break
|
||||
try {
|
||||
Thread.sleep(nextPrintTime - now)
|
||||
}
|
||||
catch (e: InterruptedException) {
|
||||
return
|
||||
}
|
||||
}
|
||||
val bucketValues = buckets
|
||||
println("Current values: ${bucketValues.total} ${bucketValues.asList()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val IntArray.total: Long get() {
|
||||
var sum = 0L
|
||||
for (d in this) sum += d
|
||||
return sum
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val rnd = ThreadLocalRandom.current()
|
||||
val values = IntArray(NUM_BUCKETS) { rnd.nextInt() and Int.MAX_VALUE }
|
||||
println("Initial array: ${values.total} ${values.asList()}")
|
||||
val buckets = Buckets(values)
|
||||
thread(name = "equalizer") { buckets.equalize() }
|
||||
thread(name = "transferrer") { buckets.transferRandomAmount() }
|
||||
thread(name = "printer") { buckets.print() }
|
||||
}
|
||||
|
|
@ -1,72 +1,68 @@
|
|||
(de *Buckets . 15) # Number of buckets
|
||||
(seed (in "/dev/urandom" (rd 8)))
|
||||
|
||||
(de *Buckets . 15) # Number of buckets
|
||||
|
||||
# E/R model
|
||||
(class +Bucket +Entity)
|
||||
(rel key (+Key +Number)) # Key 1 .. *Buckets
|
||||
(rel val (+Number)) # Value 1 .. 999
|
||||
|
||||
|
||||
# Start with an empty DB
|
||||
(call 'rm "-f" "buckets.db") # Remove old DB (if any)
|
||||
(pool "buckets.db") # Create new DB file
|
||||
(rel key (+Key +Number)) # Key 1 .. *Buckets
|
||||
(rel val (+Number)) # Value 1 .. 999
|
||||
|
||||
# Create new DB file
|
||||
(pool (tmp "buckets.db"))
|
||||
|
||||
# Create *Buckets buckets with values between 1 and 999
|
||||
(for K *Buckets
|
||||
(new T '(+Bucket) 'key K 'val (rand 1 999)) )
|
||||
(commit)
|
||||
|
||||
|
||||
# Pick a random bucket
|
||||
(de pickBucket ()
|
||||
(db 'key '+Bucket (rand 1 *Buckets)) )
|
||||
|
||||
# Create process
|
||||
(de process (QuadFunction)
|
||||
(unless (fork)
|
||||
(seed *Pid) # Ensure local random sequence
|
||||
(loop
|
||||
(let (B1 (pickBucket) B2 (pickBucket)) # Pick two buckets 'B1' and 'B2'
|
||||
(unless (== B1 B2) # Found two different ones?
|
||||
(dbSync) # Atomic DB operation
|
||||
(let (V1 (; B1 val) V2 (; B2 val)) # Get current values
|
||||
(QuadFunction B1 V1 B2 V2) )
|
||||
(commit 'upd) ) ) ) ) ) # Close transaction
|
||||
|
||||
|
||||
# First process
|
||||
(process
|
||||
(quote (B1 V1 B2 V2)
|
||||
(cond
|
||||
((> V1 V2)
|
||||
(dec> B1 'val) # Make them closer to equal
|
||||
(inc> B2 'val) )
|
||||
((> V2 V1)
|
||||
(dec> B2 'val)
|
||||
(inc> B1 'val) ) ) ) )
|
||||
(unless (fork)
|
||||
(seed *Pid) # Ensure local random sequence
|
||||
(loop
|
||||
(let (B1 (pickBucket) B2 (pickBucket)) # Pick two buckets 'B1' and 'B2'
|
||||
(dbSync) # Atomic DB operation
|
||||
(let (V1 (; B1 val) V2 (; B2 val)) # Get current values
|
||||
(cond
|
||||
((> V1 V2)
|
||||
(dec> B1 'val) # Make them closer to equal
|
||||
(inc> B2 'val) )
|
||||
((> V2 V1)
|
||||
(dec> B2 'val)
|
||||
(inc> B1 'val) ) ) )
|
||||
(commit 'upd) # Close transaction
|
||||
(wait 1) ) ) )
|
||||
|
||||
# Second process
|
||||
(process
|
||||
(quote (B1 V1 B2 V2)
|
||||
(cond
|
||||
((> V1 V2 0)
|
||||
(inc> B1 'val) # Redistribute them
|
||||
(dec> B2 'val) )
|
||||
((> V2 V1 0)
|
||||
(inc> B2 'val)
|
||||
(dec> B1 'val) ) ) ) )
|
||||
(unless (fork)
|
||||
(seed *Pid) # Ensure local random sequence
|
||||
(loop
|
||||
(let (B1 (pickBucket) B2 (pickBucket)) # Pick two buckets 'B1' and 'B2'
|
||||
(unless (== B1 B2) # Found two different ones?
|
||||
(dbSync) # Atomic DB operation
|
||||
(let (V1 (; B1 val) V2 (; B2 val)) # Get current values
|
||||
(cond
|
||||
((> V1 V2 0)
|
||||
(inc> B1 'val) # Redistribute them
|
||||
(dec> B2 'val) )
|
||||
((> V2 V1 0)
|
||||
(inc> B2 'val)
|
||||
(dec> B1 'val) ) ) )
|
||||
(commit 'upd) # Close transaction
|
||||
(wait 1) ) ) ) )
|
||||
|
||||
# Third process
|
||||
(unless (fork)
|
||||
(loop
|
||||
(dbSync) # Atomic DB operation
|
||||
(let Lst (collect 'key '+Bucket) # Get all buckets
|
||||
(for This Lst # Print current values
|
||||
(let Lst (collect 'key '+Bucket) # Get all buckets
|
||||
(for This Lst # Print current values
|
||||
(printsp (: val)) )
|
||||
(prinl # and total sum
|
||||
(prinl # and total sum
|
||||
"-- Total: "
|
||||
(sum '((This) (: val)) Lst) ) )
|
||||
(rollback)
|
||||
(wait 2000) ) ) # Sleep two seconds
|
||||
(wait 2000) ) ) # Sleep two seconds
|
||||
|
||||
(wait)
|
||||
|
|
|
|||
45
Task/Atomic-updates/Ring/atomic-updates.ring
Normal file
45
Task/Atomic-updates/Ring/atomic-updates.ring
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
# Project : Atomic updates
|
||||
# Date : 2018/01/01
|
||||
# Author : Gal Zsolt (~ CalmoSoft ~)
|
||||
# Email : <calmosoft@gmail.com>
|
||||
|
||||
bucket = list(10)
|
||||
f2 = 0
|
||||
for i = 1 to 10
|
||||
bucket[i] = floor(random(9)*10)
|
||||
next
|
||||
|
||||
a = display("display:")
|
||||
see nl
|
||||
a = flatten(a)
|
||||
see "" + a + nl
|
||||
a = display("flatten:")
|
||||
see nl
|
||||
a = transfer(3,5)
|
||||
see a + nl
|
||||
see "19 from 3 to 5: "
|
||||
a = display(a)
|
||||
see nl
|
||||
|
||||
func display(a)
|
||||
display = 0
|
||||
see "" + a + " " + char(9)
|
||||
for i = 1 to 10
|
||||
display = display + bucket[i]
|
||||
see "" + bucket[i] + " "
|
||||
next
|
||||
see " total:" + display
|
||||
return display
|
||||
|
||||
func flatten(f)
|
||||
f1 = floor((f / 10) + 0.5)
|
||||
for i = 1 to 10
|
||||
bucket[i] = f1
|
||||
f2 = f2 + f1
|
||||
next
|
||||
bucket[10] = bucket[10] + f - f2
|
||||
|
||||
func transfer(a1,a2)
|
||||
transfer = floor(random(9)/10 * bucket[a1])
|
||||
bucket[a1] = bucket[a1] - transfer
|
||||
bucket[a2] = bucket[a2] + transfer
|
||||
Loading…
Add table
Add a link
Reference in a new issue