Version 1 of ycl coro relay

Updated 2016-04-26 05:43:33 by APN

ycl coro relay is a small but complete system that provides order/receive facilities among asynchronous coroutines. Features include timeouts, cancellation, error propagation, and scatter/gather capabilities.

Commands

accept ?spec? ?payload?
yield until called, and return a list in which the first value is the sender's information, and any subsequent values available the purposes of the current coroutine. spec is a list of names to assign from the list returned by yieldto to local variables, in the same manner as the second argument of proc, to local variables. If the last name is args, a list of remaining values is assigned to it. payload is a value to yield.
call ?spec? args
Like order, but the evaluated command does not have to call accept or use deliver, or even be a coroutine, although it can be. It's just a normal command that returns a result. Returns an order id that can passed to cancel. delay is the number of milliseconds to delay before sending evaluating the command. args is the command to evaluate.
cancel id
Cancel an order that hasn't been received. If the order has not been started, it won't be. Otherwise, any results it delivers are discarded.
deliver delay ?arg ...?
Deliver an order. delay is the number of milliseconds to delay before mmaking the delivery. The first arg is a command prefix for the sender. It's typically acquired as the first value in the list returned by accept. Remaining args are passed as additional in the command. In other words, items in the first value are expanded and replace the first value, and the resulting list is the command .
last
Returns the order id of the last delivered task.
order delay ?arg ...`?
Place a new order and return an order id that can be passed to cancel. Number of milliseconds to wait before placing the order. If $delay contains more than one item, the second item is the maximum number of milliseconds alloted for delivery, order times out, after which the order is not be initiated if it hasn't been started, and if it has, any subsequent deliveries are discarded. If there is a third item, the second item is the maximum number of milliseconds alllotted for the order to be started, and the third item is the maximum number of milliseonds alloted for delivery. If the completion timeout occurs before the order is complete, any subsequent delivery is discarded.
receive
Yield until a previously-placed order comes in, and then return the value and the options dictionary of that order.
switch ?option value ...?
Yield until an order was received, and respond to it according to the first word of the order. routes is a dictionary of words and corresponding scripts. These are merged into the default routes.

Example

#! /bin/env tclsh

package require {ycl coro relay}

namespace import [yclprefix]::coro::relay

proc adder {} {
    while 1 {
        relay accept {sender args}
        relay deliver 0 $sender [::tcl::mathop::+ {*}$args]
    }
}

proc multiplier {} {
    while 1 {
        relay accept {sender args}
        relay deliver 0 $sender [::tcl::mathop::* {*}$args]
    }
}

after 0 [list coroutine main apply [list {argv0 argv} {
    coroutine a1 adder
    coroutine m1 multiplier
    set count 10
    set tasks {}
    for {set num1 0; set num2 100} {$num1 < $count} {incr num1; incr num2} {
        dict set tasks add [relay order 0 a1 $num1 $num2] {}
        dict set tasks mult [relay order 0 m1 $num1 $num2] {}
    }
    while {[llength [dict keys [dict get $tasks add]]]
        || [llength [dict keys [dict get $tasks mult]]]} {
        set received [relay receive]
        foreach type {add mult} {
            if {[dict exists $tasks $type [relay last]]} {
                dict unset tasks $type [relay last]
                lappend ${type}_results $received
            }
        }
    }
    rename a1 {}
    rename m1 {}
    puts [list {add results} $add_results]
    puts [list {mult results} $mult_results]
    exit 0

} [namespace current]] $argv0 $argv]


vwait forever

result:

{add results} {100 102 104 106 108 110 112 114 116 118}
{mult results} {0 101 204 309 416 525 636 749 864 981}

APN How compatible is this system with the coroutine package in tcllib ? In particular, can one of these cooperating coroutines call commands from that package such as coroutine::util gets ? Or would there be a conflict between "competing" yields?