Package: aiocells
aiocellsis a package that provides tools for synchronous and asynchronous
execution of nodes in a dependency graph.Contents:ExamplesDevelopment InstallationExamplesHello worldHere is the code for thefirst demo.#!/usr/bin/env python3importaiocellsdefhello_world():print("Hello, world!")defmain():graph=aiocells.DependencyGraph()# The node can be any callable, in this case a function.graph.add_node(hello_world)aiocells.compute_sequential(graph)This issynchronousgraph computation. There is only one node in the graph.
It is a function that prints a message. Synchronous nodes must becallable.Defining ordering constraintsHere isdemo 4. It shows how edges between nodes
are defined:#!/usr/bin/env python3importtimeimportaiocellsdefmain():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# relationshipsprint_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)In this case, there are three nodes. After the nodes are added, we define
precedence relationships between them. When the graph is computed, it is
done so in a way that honours the precedence relationships.Asynchronous nodesBelow is the code fordemo_5. Note the use ofasyncio.sleep,functools.partialandaiocells.async_compute_sequential.#!/usr/bin/env python3importasynciofromfunctoolsimportpartialimportaiocells# This example demonstrates graph nodes that are coroutines. We use# a different computer; one that know how to deal with coroutines.defmain():graph=aiocells.DependencyGraph()# First, we add a lambda functionbefore_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 functionsleep_2=partial(asyncio.sleep,2)# Finally, another lambda functionwake_up=graph.add_node(lambda:print("Woke up!"))# Here, 'sleep' will implicitly be added to the graph because it is# part of the precedence relationshipgraph.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))Concurrent computationdemo 6is a an example of graph thatcouldbe
computed concurrently but is not due to the use ifasync_compute_sequential.importasynciofromfunctoolsimportpartialimportaiocellsdefcreate_graph(stopwatch):graph=aiocells.DependencyGraph()# The method to start the stopwatchstart_stopwatch=stopwatch.start# Two sleeps. Note that they are asyncio.sleepsleep_1=partial(asyncio.sleep,1)sleep_2=partial(asyncio.sleep,2)# The method to stop the stopwatchstop_stopwatch=stopwatch.stop# Start the stopwatch before the first sleepgraph.add_precedence(start_stopwatch,sleep_1)# Stop the stopwatch after the first sleepgraph.add_precedence(sleep_1,stop_stopwatch)# Start the stopwatch before the second sleepgraph.add_precedence(start_stopwatch,sleep_2)# Stop the stopwatch after the second sleepgraph.add_precedence(sleep_2,stop_stopwatch)# Note that there is no precedence relationship between the two# sleeps.returngraphdefmain():stopwatch=aiocells.Stopwatch()graph=create_graph(stopwatch)# Even though the graph is a diamond (the sleeps do no depend on each# other and _could_ be executed concurrenty, `async_compute_sequential`# does not support concurrent execution. Thus, the execution time is# about 3 seconds, the sum of the two sleeps.print("Two async sleeps computed sequentially.")print("Total time should take about 3 seconds...")asyncio.run(aiocells.async_compute_sequential(graph))print("Computation with `async_compute_sequential` took"f"{stopwatch.elapsed_time()}")demo_7is the same graph as above but computed
concurrently withasync_compute_concurrent.#!/usr/bin/env python3importasyncioimportaiocellsimportaiocells.demo_6asdemo_6defmain():stopwatch=aiocells.Stopwatch()graph=demo_6.create_graph(stopwatch)# Here, we run the same graph as the previous demo but we use# 'async_compute_concurrent' which will run the two sleeps concurrently.# Thus, the execution time will be around 2 seconds, the maximum of# the two sleeps.print("Running previous demo's graph concurrently.")print("Total execution time should be about 2 seconds...")asyncio.run(aiocells.async_compute_concurrent(graph))print("Computation with `async_compute_concurrent` took"f"{stopwatch.elapsed_time()}")Development InstallationThere is aMakefilein the repository. The default target will initialise
a virtual environment, install dependencies into that environment and then
test the code. It requiresPython 3.8,virtualenvandpipto be
installed. If those are missing, it will print suggestions on how to address
the problem.$makeActivating the virtual environment and running the demosThe default make target will generate a file calledactivate_aiocells. To
activate the virtual environment:$sourceactivate_aiocellsOnce you've done that, you should have the following command available:$aiocellsdemo-1Tab completionactivate_aiocellswill enable tab completion foraiocells:$aiocells<TAB>Editable installationThe package will be installed in the virutal environment usingpip --editable. This means that modifications to the code will be immediately
available.To test this, try modifyingsrc/aiocells/demo_1.pyto print a different
message. You should be able to immediately run the demo and see the new
message:$aiocellsdemo-1