benefits - modrpc/info GitHub Wiki

ModPy has been inspired by many existing programming languages and software tools. Originally, this private project was started as a simpler alternative to IoT frameworks such as AllJoyn and IoTivity. Also, I found that robot control software, ROS, have a lot of similarities to this.

The reason I chose coroutines as the main vehicle is my experience with Verilog hardware description language. Hardware designers, say ARM chip developers, use Verilog to describe the chip, which is eventually synthesized to hundreds of millions of gates. A Verilog code for an ARM chip basically describes countless number of processes, which interact with each other. For example, when a process assigns a value to a variable, another process which has been waiting for the value change wakes up and perform some computation. A chip is a truly-massive concurrent and parallel system of interdependnt processes.

I had an impression that developing a distributed software is very similar to such hardware development. Basically, building a hardware system is about building a massive number of interacting finite state machines. Think about programming the Raft distrubted consensus protocol.

Table of Contents

Complex finite state machine

@modpy.proc
def RaftProtocol():
  while True:
     event = modpy.waitfor("node0:ev0", "node1:ev1"):
     if (state == 0):
       if (event.key == "node0:ev0"):
          state = 1;
       elif (event.key == 'node1:ev1"):
          state = 2;
     elif (state == 1):
       ...
     else:

Another example shows a simple resource discovery protocol. It broadcasts a function call find_ersource to all nodes in the network and takes the first result.

@modpy.func
def ResourceDiscoveryProtocol(service):
  await modpy.call("*/find_resource", "compute_factorial")
  event = await modpy.waitfor("*/report_resource")
  print("compute_factorial resouce found at:", event.value)

@modpy.event
def report_resource():
   return True

@modpy.func  
def lookup_resource(name):
   if modpy.has_resource(name):
      await modpy.fire("report_resource", modpy.self_nodename())

Dynamic

Unlike some distributed frameworks like GRPC, adding a resource does not require defining the "interface" of the services e.g. by providing signature of the functions. Somewhat loose analogy with dynamically-typed languages like Python and statically-typed languages like Java. One of the design goals of ModPy (and ModRPC) was to make it simple to use -- less number of steps to take to run a node, also reduce the amount of code. Of course, there are downside of this approach (e.g. burden of type checking is delegated to the user) but I believe that there are many applications which would benefit from this simplicity.

Multiple event loops

Essentially, a ModPy process is an event loop. Think about creating 100 different asyncio event loop which performs some independent work. Then, compare that with createing 100 ModPy processes, which is much simpler since we only need to define 100 python functions with the @modpy.func decorator.

Sometimes, rather than developing 5 different event loops which reacts to a single remote event, developing a single event loop which reacts to 5 remote events can be easier. This is because sometimes interaction between event loops can be different to implement.

Guarded command

One of the strong points of Golang is its support for select over channels. ModPy's waitfor(ev1, ev2) mimicks such behavior.

I know there are some alternatives such as goless but I wanted a lightweight method which does not require installation of Stackless, etc.

Finite-state machine decomposition

An important benefit of ModPy is to allow users to describe processes where a process is essentially an event loop which reacts to events. Consider developing an event loop which reacts to 100 different events, which amounts to building a finite-state machine with 100 different inputs. The state space that should be maintained can be huge leading to a very complicated code. It can be easier to break the event loop to, say 20, smaller event loops, each only needs to handle a few events. This has long been known as finite-state machine decomposition in digital logic design community.

⚠️ **GitHub.com Fallback** ⚠️