Skip to content

Commit 9d943f4

Browse files
committed
discrete event simulation
1 parent 197b405 commit 9d943f4

13 files changed

+232
-1
lines changed

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ greenlet
33
kaleido
44
pandas
55
plotly
6+
prettytable
7+
py-des-lib
68
pydot
79
pyfakefs
810
pytest

src/eventsim/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
TARGETS=\
2+
multiprocess.out \
3+
wait_and_work.out \
4+
wait_event.out \
5+
wait_work_record.out
6+
7+
include ../../examples.mk

src/eventsim/index.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
---
2-
title: "Discrete Event Simulator"
2+
title: "Discrete Event Simulation"
33
abstract: >
44
FIXME
55
syllabus:
66
- FIXME
77
---
88

99
[%fixme "create discrete event simulator" %] [%issue 56 %]
10+
11+
- Basic ideas of discrete event simulation
12+
- `wait_and_work.py`: work a fixed time, wait a fixed time
13+
- `wait_work_record.py`: record events and display table of results
14+
- `multiprocess.py`: two independent processes
15+
- `wait_event.py`: one waits for the other to finish
16+
- But events happen once
17+
- `producer_consumer.py`: eventually producer can only run as fast as consumer

src/eventsim/multiprocess.out

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
| time | component | message |
2+
|----: | :---------| :----------|
3+
| 0 | Worker.0 | start work |
4+
| 0 | Worker.1 | start work |
5+
| 2 | Worker.0 | start work |
6+
| 2 | Worker.1 | start work |
7+
| 4 | Worker.0 | start work |
8+
| 4 | Worker.1 | start work |
9+
| 6 | Worker.0 | finished |
10+
| 6 | Worker.1 | finished |

src/eventsim/multiprocess.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from pydes import Component, Simulator
2+
from util import format_log
3+
4+
5+
class Worker(Component):
6+
NUM_STEPS = 3
7+
WORK_TIME = 2
8+
9+
def __init__(self, sim):
10+
self._sim = sim
11+
12+
def main(self):
13+
for i in range(self.NUM_STEPS):
14+
self._sim.record(self, "start work")
15+
self._sim.sleep(self.WORK_TIME)
16+
self._sim.record(self, "finished")
17+
18+
19+
def simulate():
20+
sim = Simulator(trace=False)
21+
sim.schedule(Worker(sim))
22+
sim.schedule(Worker(sim))
23+
sim.run()
24+
print(format_log(sim.records()))
25+
26+
27+
if __name__ == "__main__":
28+
simulate()

src/eventsim/producer_consumer.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from pydes import Component, Queue, Simulator
2+
from util import format_log
3+
4+
5+
NUM_ITEMS = 10
6+
QUEUE_SIZE = 3
7+
8+
9+
class Producer(Component):
10+
WORK_TIME = 2
11+
12+
def __init__(self, sim, queue):
13+
self._sim = sim
14+
self._queue = queue
15+
16+
def main(self):
17+
for i in range(NUM_ITEMS):
18+
self._sim.sleep(self.WORK_TIME)
19+
self._sim.record(self, f"produce={i} queue@{self._queue.size()}")
20+
self._queue.put(i)
21+
22+
23+
class Consumer(Component):
24+
WORK_TIME = 4
25+
26+
def __init__(self, sim, queue):
27+
self._sim = sim
28+
self._queue = queue
29+
30+
def main(self):
31+
for i in range(NUM_ITEMS):
32+
value = self._queue.get()
33+
self._sim.record(self, f"consume={i}")
34+
self._sim.sleep(self.WORK_TIME)
35+
36+
37+
def simulate():
38+
sim = Simulator(trace=False)
39+
queue = Queue(sim, QUEUE_SIZE)
40+
sim.schedule(Producer(sim, queue))
41+
sim.schedule(Consumer(sim, queue))
42+
sim.run()
43+
print(format_log(sim.records()))
44+
45+
46+
if __name__ == "__main__":
47+
simulate()

src/eventsim/util.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from prettytable import MARKDOWN, PrettyTable
2+
3+
4+
FIELDS = {
5+
"time": "r",
6+
"component": "l",
7+
"message": "l",
8+
}
9+
10+
11+
def format_log(records):
12+
table = PrettyTable(field_names=FIELDS.keys())
13+
table.set_style(MARKDOWN)
14+
for field, align in FIELDS.items():
15+
table.align[field] = align
16+
for rec in records:
17+
table.add_row([rec.time, str(rec.component), rec.value])
18+
return table

src/eventsim/wait_and_work.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
start to work at 0
2+
start to work at 2
3+
start to work at 4
4+
finished working at 6

src/eventsim/wait_and_work.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from pydes import Component, Simulator
2+
3+
4+
class Worker(Component):
5+
NUM_STEPS = 3
6+
WORK_TIME = 2
7+
8+
def __init__(self, sim):
9+
self._sim = sim
10+
11+
def main(self):
12+
for i in range(self.NUM_STEPS):
13+
print(f"start to work at {self._sim.now()}")
14+
self._sim.sleep(self.WORK_TIME)
15+
print(f"finished working at {self._sim.now()}")
16+
17+
18+
def simulate():
19+
sim = Simulator()
20+
worker = Worker(sim)
21+
sim.schedule(worker)
22+
sim.run()
23+
24+
25+
if __name__ == "__main__":
26+
simulate()

src/eventsim/wait_event.out

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
| time | component | message |
2+
|----: | :---------| :----------|
3+
| 0 | Worker.0 | start work |
4+
| 0 | Worker.1 | start work |
5+
| 2 | Worker.1 | start work |
6+
| 4 | Worker.1 | start work |
7+
| 6 | Worker.1 | finished |
8+
| 6 | Worker.0 | start work |
9+
| 8 | Worker.0 | start work |
10+
| 10 | Worker.0 | start work |
11+
| 12 | Worker.0 | finished |

src/eventsim/wait_event.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
from pydes import Component, Event, Simulator
2+
from util import format_log
3+
4+
5+
class Worker(Component):
6+
NUM_STEPS = 3
7+
WORK_TIME = 2
8+
9+
def __init__(self, sim, event, wait_at_start):
10+
self._sim = sim
11+
self._event = event
12+
self._wait_at_start = wait_at_start
13+
14+
def main(self):
15+
if self._wait_at_start:
16+
self._sim.record(self, "start work")
17+
self._event.wait()
18+
for i in range(self.NUM_STEPS):
19+
self._sim.record(self, "start work")
20+
self._sim.sleep(self.WORK_TIME)
21+
self._sim.record(self, "finished")
22+
if not self._wait_at_start:
23+
self._event.set()
24+
25+
26+
def simulate():
27+
sim = Simulator(trace=False)
28+
event = Event(sim)
29+
sim.schedule(Worker(sim, event, True))
30+
sim.schedule(Worker(sim, event, False))
31+
sim.run()
32+
print(format_log(sim.records()))
33+
34+
35+
if __name__ == "__main__":
36+
simulate()

src/eventsim/wait_work_record.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| time | component | message |
2+
|----: | :---------| :----------|
3+
| 0 | Worker.0 | start work |
4+
| 2 | Worker.0 | start work |
5+
| 4 | Worker.0 | start work |
6+
| 6 | Worker.0 | finished |

src/eventsim/wait_work_record.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from pydes import Component, Simulator
2+
from util import format_log
3+
4+
5+
class Worker(Component):
6+
NUM_STEPS = 3
7+
WORK_TIME = 2
8+
9+
def __init__(self, sim):
10+
self._sim = sim
11+
12+
def main(self):
13+
for i in range(self.NUM_STEPS):
14+
self._sim.record(self, "start work")
15+
self._sim.sleep(self.WORK_TIME)
16+
self._sim.record(self, "finished")
17+
18+
19+
def simulate():
20+
sim = Simulator(trace=False)
21+
worker = Worker(sim)
22+
sim.schedule(worker)
23+
sim.run()
24+
print(format_log(sim.records()))
25+
26+
27+
if __name__ == "__main__":
28+
simulate()

0 commit comments

Comments
 (0)