def schan_test(): print("************************************************************") print("Simple channel test") @process def writer(p, ch): pref = " " * p * 2 for i in range(10): val = (p, i) print(f"{pref} W {p} -> {val}") ch.write(val) print(f"{pref} W {p} done") time.sleep(random.random() * 0.5 + 0.5) @process def reader(p, ch): pref = " " + " " * p * 2 time.sleep(0.1) for i in range(10): print(f"{pref} R {p} waiting") val = ch.read() print(f"{pref} R {p} got {val}") time.sleep(random.random() * 0.5 + 0.5) ch = Channel() Parallel(writer(1, ch), reader(1, ch), writer(2, ch), reader(2, ch)) print("All done")
def ParDelta2(cin, cout1, cout2): """Parallel version of Delta2""" @process def writer(ch, val): ch(val) for t in cin: # NB: cout1(t) generates a coroutine, which is equivalent with a CSP process. # This is therefore safe to do. Parallel(writer(cout1, t), writer(cout2, t), check_poison=True)
def sguard_test(): print("************************************************************") print("Simple guarded channel test") @process def writer(p, cout): pref = " " * p * 2 for i in range(10): val = (p, i) print(f"{pref} W {p} -> {val}") cout(val) print(f"{pref} W {p} write done") time.sleep(random.random() * 0.5 + 0.5) print(f"{pref} W {p} finishing") # cout.poison() @process def reader(p, cin): pref = " " * p * 2 for i, m in enumerate(cin): print(f"{pref} R {p} got {m} {i}") if i == 9: break @process def gread(p, cin): pref = " " * p * 2 alt = Alternative(cin) for i in itertools.count(): if i == 10: break # TODO poison doesn't work for alt.select yet print(f"{pref} AR {p} waiting") with alt as (g, val): print(f"{pref} AR {p} got {val} from {g}") @process def gwrite(p, cout): pref = " " * p * 2 for i in range(10): val = (p, i) print(f"{pref} AW {p} -> {val}") g = cout.alt_pending_write(val) alt = Alternative(g) alt.select() print(f"{pref} AW {p} done") time.sleep(random.random() * 0.5 + 0.5) print(f"{pref} AW {p} finishing") # cout.poison() ch = Channel() Parallel(writer(1, ch.write), reader(2, ch.read), gread(3, ch.read), gwrite(4, ch.write)) print("All done")
def CommsTimeBM(run_no, Delta2=Delta2): # Create channels a = Channel("a") b = Channel("b") c = Channel("c") d = Channel("d") rets = Parallel(Prefix(c.read, a.write, prefixItem=0), # initiator Delta2(a.read, b.write, d.write), # forwarding to two Successor(b.read, c.write), # feeding back to prefix consumer(d.read, run_no)) # timing process return rets[-1]
def run_timing(read_end, write_end): dts = [] for i in range(100): N = 1000 print(f" Run {i}:", end="") #t1 = time.time() Parallel(writer_timed(N, write_end), reader_timed(N, read_end)) #t2 = time.time() dt_ms = (t2 - t1) * 1000 dt_op_us = (dt_ms / N) * 1000 print(f" DT = {dt_ms:8.3f} ms per op: {dt_op_us:8.3f} us") dts.append(dt_op_us) print(" -- min {:.3f} avg {:.3f} max {:.3f} ".format( min(dts), avg(dts), max(dts)))
def ParDelta2(cin, cout1, cout2): # We need two helper processes (_sender) to send on the two output channels in parallel. # The overhead of this is probably going to be fairly high as we're starting and stopping threads for every iteration. # We could optimize it with re_usable threads, but if we create a separate channel to each of them we're more or # less recreating the problem with another mini-delta in the middle. # The other alternative is threads that don't disappear until we leave the context they were created in and that can be # re-started inside a Par (or similar) context. This quickly complicates the API and could make it harder to understand. @process def _sender(ochan, val): ochan(val) while True: t = cin() for c in [cout1, cout2]: # TODO: Had to add a poison workaround as Parallel and Process don't propagate poison by re-raising # exceptions. Instead, they rely on the procesess catching poison by accessing a channel. # Delta2 will only be poisoned directly when trying to read the cin channel, so we need to # manually check the other two here and raise it manually if necessary. # We need a solution that works both when we want to propagate poison and when we want to filter it. if c._chan.poisoned: raise ChannelPoisonException() Parallel(_sender(cout1, t), _sender(cout2, t))
t1 = time.time() for i in range(N): cout(i) @process def reader_timed(N, cin): global t2 for i in range(N + 10): v = cin() t2 = time.time() N = 10 c = One2OneChannel('a') Parallel(writer(N, c.write), reader_verb(N, c.read)) def run_timing(read_end, write_end): dts = [] for i in range(100): N = 1000 print(f" Run {i}:", end="") #t1 = time.time() Parallel(writer_timed(N, write_end), reader_timed(N, read_end)) #t2 = time.time() dt_ms = (t2 - t1) * 1000 dt_op_us = (dt_ms / N) * 1000 print(f" DT = {dt_ms:8.3f} ms per op: {dt_op_us:8.3f} us") dts.append(dt_op_us) print(" -- min {:.3f} avg {:.3f} max {:.3f} ".format(