def main(): graph = aiocells.DependencyGraph() clock = aiocells.ModClock() variable_1 = aiocells.ModPlace(clock) variable_2 = aiocells.ModPlace(clock) printer_1 = aiocells.ModPrinter(clock, variable_1, "variable_1 changed to {value}") printer_2 = aiocells.ModPrinter(clock, variable_2, "variable_2 changed to {value}") graph.add_precedence(variable_1, printer_1) graph.add_precedence(variable_2, printer_2) print("Nothing has changed:") aiocells.compute_sequential(graph) variable_1.value = 1 variable_2.value = 2 print("Both variables:") aiocells.compute_sequential(graph) variable_1.value = 3 print("variable_1 only:") aiocells.compute_sequential(graph)
async def async_main(): # Tests an async internal node in a flow graph graph = aiocells.DependencyGraph() time = aiocells.Place() printer = graph.add_node(functools.partial(async_printer, time)) graph.add_precedence(time, printer) # This example will continue until it is interrupted with Ctrl-C. # # Note that marking a function to be repeater function currently only # affects the behaviour of 'compute_flow' and not any of the other # `compute` functions. print() print("Demo will complete in 10 iterations. Ctrl-C to cancel.") print() repeat_timer = functools.partial(aiocells.timer, 1, time) graph.add_precedence(repeat_timer, time) iteration_count = 0 while await aiocells.compute_flow(graph): iteration_count += 1 if iteration_count > 10: await aiocells.cancel_flow(graph)
def create_graph(stopwatch): graph = aiocells.DependencyGraph() # The method to start the stopwatch start_stopwatch = stopwatch.start # Two sleeps. Note that they are asyncio.sleep sleep_1 = partial(asyncio.sleep, 1) sleep_2 = partial(asyncio.sleep, 2) # The method to stop the stopwatch stop_stopwatch = stopwatch.stop # Start the stopwatch before the first sleep graph.add_precedence(start_stopwatch, sleep_1) # Stop the stopwatch after the first sleep graph.add_precedence(sleep_1, stop_stopwatch) # Start the stopwatch before the second sleep graph.add_precedence(start_stopwatch, sleep_2) # Stop the stopwatch after the second sleep graph.add_precedence(sleep_2, stop_stopwatch) # Note that there is no precedence relationship between the two # sleeps. return graph
async def async_main(): clock = aiocells.ModClock() graph = aiocells.DependencyGraph() # Here, we simplify the previous demo by using a single variable to # store the time and a single printer to announce the modifications # when they happen. Because we are using 'compute_flow', the graph # is computed when any of the timers go off. time = aiocells.ModVariable(clock) printer = aiocells.ModPrinter(clock, time, "time changed to {value}") graph.add_precedence(time, printer) # Set the time after 1 second timer_1 = functools.partial(aiocells.timer, 1, time) graph.add_precedence(timer_1, time) # Set the time after 3 seconds timer_3 = functools.partial(aiocells.timer, 3, time) graph.add_precedence(timer_3, time) print() print("Demo will complete in 10 iterations. Ctrl-C to cancel.") print() iteration_count = 0 while await aiocells.compute_flow(graph): iteration_count += 1 if iteration_count > 10: await aiocells.cancel_flow(graph)
def main(): graph = aiocells.DependencyGraph() # First, we add a lambda function before_sleep = graph.add_node(lambda: print("Sleeping...")) # Second, we create a coroutine function using functools.partial. This # is the closest we can get to a lambda for an async function sleep_2 = partial(asyncio.sleep, 2) # Finally, another lambda function wake_up = graph.add_node(lambda: print("Woke up!")) # Here, 'sleep' will implicitly be added to the graph because it is # part of the precedence relationship graph.add_precedence(before_sleep, sleep_2) graph.add_precedence(sleep_2, wake_up) # Here, we use the `async_compute_sequential`, which, like # `compute_sequential`, call the nodes in a topologically correct sequence. # However, whereas `compute_sequential` only supports vanilla callables, # `async_compute_sequential` additionally supports coroutine functions, # as defined by `inspect.iscoroutinefunction`. However, the execution is # still sequential. Each coroutine function is executed using 'await' and # must complete before the next node is executed. The function # `async_compute_sequential` is a coroutine and must be awaited. Here, # we simply pass it to `asyncio.run`. asyncio.run(aiocells.async_compute_sequential(graph))
def main(): graph = aiocells.DependencyGraph() # In this example, we add a instance of a callable object rather than # a function node = graph.add_node(HelloWorld()) aiocells.compute_sequential(graph)
def create_graph(stopwatch): graph = aiocells.DependencyGraph() start_stopwatch = stopwatch.start stop_stopwatch = stopwatch.stop for t in range(100000): sleep_1 = partial(asyncio.sleep, 1) graph.add_precedence(start_stopwatch, sleep_1) graph.add_precedence(sleep_1, stop_stopwatch) return graph
def create_graph(stopwatch): graph = aiocells.DependencyGraph() start_stopwatch = graph.add_node(stopwatch.start) stop_stopwatch = graph.add_node(stopwatch.stop) for i in range(10): subgraph = graph.add_node(partial(run_subgraph, f"{i}")) graph.add_precedence(start_stopwatch, subgraph) graph.add_precedence(subgraph, stop_stopwatch) return graph
def subgraph(name, period): clock = aiocells.ModClock() graph = aiocells.DependencyGraph(name=name) time = aiocells.ModPlace(clock) printer = aiocells.ModPrinter(clock, time, f"time in \"{name}\" changed to {{value}}") graph.add_precedence(time, printer) timer = functools.partial(aiocells.timer, period, time) graph.add_precedence(timer, time) return graph
def create_graph(stopwatch): graph = aiocells.DependencyGraph() start_stopwatch = stopwatch.start stop_stopwatch = stopwatch.stop for t in range(100000): def null(): pass graph.add_precedence(start_stopwatch, null) graph.add_precedence(null, stop_stopwatch) return graph
async def async_main(): graph = aiocells.DependencyGraph(name="async_main") subgraph_1 = subgraph("graph_1", 0.7) subgraph_2 = subgraph("graph_2", 1.5) graph.add_node(functools.partial(aiocells.compute_flow, subgraph_1)) graph.add_node(functools.partial(aiocells.compute_flow, subgraph_2)) print() print("Demo will complete in 10 iterations. Ctrl-C to cancel.") print() iteration_count = 0 while await aiocells.compute_flow(graph): iteration_count += 1 if iteration_count > 10: await aiocells.cancel_flow(graph)
def main(): graph = aiocells.DependencyGraph() # 'add_node' always returns the node that has just been added, in this # case the lambda functions. We will use this below to define precedence # relationships print_sleeping = graph.add_node(lambda: print("Sleeping...")) sleep = graph.add_node(lambda: time.sleep(2)) print_woke_up = graph.add_node(lambda: print("Woke up!")) print("Define the precedence relationships...") graph.add_precedence(print_sleeping, sleep) graph.add_precedence(sleep, print_woke_up) # Now, after we've defined the precedence relationships, we use the # simplest computer to compute the graph. The nodes will be called in # an order that is consistent with the precedence relationships. # Specifically, the nodes are executed in topological order. aiocells.compute_sequential(graph)
def create_graph(stopwatch): graph = aiocells.DependencyGraph() start_stopwatch = stopwatch.start # Note that these two sleeps are just lambdas. They are vanilla # callables and not coroutine functions. Thus, they cannot be run # concurrently. Thus, the total run time will be about 3 seconds even # if we use the concurrent computer. sleep_1 = graph.add_node(lambda: time.sleep(1)) sleep_2 = graph.add_node(lambda: time.sleep(2)) stop_stopwatch = stopwatch.stop graph.add_precedence(start_stopwatch, sleep_1) graph.add_precedence(sleep_1, stop_stopwatch) graph.add_precedence(start_stopwatch, sleep_2) graph.add_precedence(sleep_2, stop_stopwatch) return graph
def main(): graph = aiocells.DependencyGraph() time = aiocells.Place() # 'aio.timer' will put the current time in the 'time' variable when # one second has expired timer = functools.partial(aiocells.timer, 1, time) printer = aiocells.print_value(time, "variable changed to {value}") graph.add_precedence(timer, time) graph.add_precedence(time, printer) logger.debug("graph: %s", graph) logger.info("First computation...") asyncio.run(aiocells.async_compute_concurrent(graph)) logger.debug("graph: %s", graph) logger.info("Second computation...") asyncio.run(aiocells.async_compute_concurrent(graph)) logger.debug("graph: %s", graph)
def main(): graph = aiocells.DependencyGraph() time = aiocells.Place() timer = TimerObject(time) # Here, we bind the coroutine method with the object compute_timer = functools.partial(TimerObject.compute, timer) printer = aiocells.print_value(time, "variable changed to {value}") graph.add_precedence(compute_timer, time) graph.add_precedence(time, printer) logger.debug("graph: %s", graph) logger.info("First computation...") asyncio.run(aiocells.async_compute_concurrent(graph)) logger.debug("graph: %s", graph) logger.info("Second computation...") asyncio.run(aiocells.async_compute_concurrent(graph)) logger.debug("graph: %s", graph)
async def async_main(iterations=None): iterations = iterations if iterations is not None else 10 clock = aiocells.ModClock() graph = aiocells.DependencyGraph(name="demo_1") # Two completely unrelated sequences are added to the graph. They # run concurrently. time_1 = aiocells.ModPlace(clock) timer_1 = functools.partial(aiocells.timer, 1, time_1) printer_1 = aiocells.ModPrinter(clock, time_1, "time_1 changed to {value}") graph.add_precedence(timer_1, time_1) graph.add_precedence(time_1, printer_1) time_3 = aiocells.ModPlace(clock) timer_3 = functools.partial(aiocells.timer, 3, time_3) printer_3 = aiocells.ModPrinter(clock, time_3, "time_3 changed to {value}") graph.add_precedence(timer_3, time_3) graph.add_precedence(time_3, printer_3) # With a flow computation, when any of the input nodes returns, all # non-input nodes are computed in topological order. When this happens, we # are generally only interested in nodes that change as a result of the # input node returning. So, in this case, we see a message from "time_1" # every second and a message from "time_3" every 3 seconds print() print("Demo will complete in 10 iterations. Ctrl-C to cancel.") print() iteration_count = 0 while await aiocells.compute_flow(graph): iteration_count += 1 if iteration_count > iterations: await aiocells.cancel_flow(graph)
def main(): graph = aiocells.DependencyGraph() # The node can be any callable, in this case a function. graph.add_node(hello_world) aiocells.compute_sequential(graph)
async def run_subgraph(name): graph = aiocells.DependencyGraph() sleep_2 = partial(asyncio.sleep, 2) graph.add_node(sleep_2) print(f"Running subgraph {name}") await aiocells.async_compute_concurrent(graph)
def main(): graph = aiocells.DependencyGraph() graph.add_node(lambda: time.sleep(2)) print("This computation will take about 2 seconds because of the sleep") aiocells.compute_sequential(graph)