Example #1
0
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")
Example #2
0
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)
Example #3
0
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")
Example #4
0
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]
Example #5
0
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)))
Example #6
0
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))
Example #7
0
    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(