June 2018 Update

This commit is contained in:
Ingy döt Net 2018-06-22 20:57:24 +00:00
parent ba8067c3b7
commit 22f33d4004
5278 changed files with 84726 additions and 14379 deletions

View 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))))))

View 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

View 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()

View 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() }
}

View file

@ -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)

View 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