Sorta, kinda, working version of actor model and state-dispatch model

This commit is contained in:
aewens 2019-08-14 16:08:01 -05:00
parent b3a44bc9f2
commit 41e75554ed

View File

@ -1,91 +1,67 @@
from abots.helpers import generator from abots.helpers import generator, infinitedict
from psutil import Process as PSProcess #from queue import Queue, Empty
from queue import Queue, Empty from time import monotonic as time
from time import sleep, monotonic as time from gevent import Greenlet, sleep, joinall
from os import getloadavg from gevent.queue import Queue, Empty
from collections import deque
from multiprocessing import cpu_count
actions = dict() hooks = dict()
events = Queue()
last = time() def reducer(state, action):
ticks = deque() name = action.get("name")
ticks.append(0) data = action.get("data")
max_loadavg = float(cpu_count()) if name == "ADD":
threshold = 15.0 state["counter"] = state.get("counter", 0) + data
max_cpu = 25.0
sleeping = 0.001 return state
sleepings = list()
stats = list() @generator
magic = 0 def dispatcher():
step = 0.0001 state, action = (yield)
max_ticks = 0 state = state.copy() if state else infinitedict()
loops = 0 reducer(state, action)
proc = PSProcess()
cpu = proc.cpu_percent() dispatch = dispatcher()
def register(func): def register(func):
actions[func.__name__] = generator(func) f = func()
f.start()
hooks[func.__name__.lower()] = f
return func return func
@register def loop():
def push(): joinall([func for name, func in hooks.items()])
message = (yield)
time1 = round(sleeping, 6) def transmit(hook_name, message):
time2 = round(magic, 6) hook = hooks.get(hook_name)
print("push", message, time1, time2, loops, max_ticks, cpu) inbox = getattr(hook, "inbox", None)
event = "pull", ticks[-1] put = getattr(inbox, "put", None)
events.put_nowait(event) if callable(put):
put(message)
class Actor(Greenlet):
def __init__(self):
self.inbox = Queue()
Greenlet.__init__(self)
def send(self, message):
NotImplemented
def _run(self):
self.running = True
while self.running:
message = self.inbox.get()
self.send(message)
@register @register
def pull(): class Ping(Actor):
message = (yield) def send(self, message):
time1 = round(sleeping, 6) print(message)
time2 = round(magic, 6) dispatch("pong", "ping")
print("pull", message, time1, time2, loops, max_ticks, cpu) sleep(0)
event = "push", ticks[-1]
events.put_nowait(event)
seed = "push", ticks[-1] @register
events.put_nowait(seed) class Pong(Actor):
done = time() + 60 def send(self, message):
prev_cpu = 0 print(message)
prev_loadavg = 0 dispatch("ping", "pong")
while True: #time() < done: sleep(0)
if time() >= last + 1:
ticks.append(0)
last = time()
loadavg = getloadavg()[0]
diff_loadavg = loadavg - prev_loadavg
prev_loadavg = loadavg
if loadavg >= max_loadavg and diff_loadavg > 0:
sleeping = sleeping + step * 10
else:
cpu = proc.cpu_percent()
diff_cpu = cpu - prev_cpu
prev_cpu = cpu
if cpu >= max_cpu and diff_cpu > 0:
sleeping = sleeping + step * 10
elif cpu >= threshold and diff_cpu > 0:
sleeping = sleeping + step
elif sleeping - step >= 0 and diff_cpu < 0:
sleeping = sleeping - step
sleepings.append(sleeping)
stat = sum(sleepings) / len(sleepings)
stats.append(stat)
magic = sum(stats) / len(stats)
max_ticks = max(ticks)
loops = loops + 1
try:
event = events.get_nowait()
source, message = event
action = actions.get(source)
if action:
action().send(message)
except Empty:
break
sleep(sleeping)
ticks[-1] = ticks[-1] + 1