1: enum { PING = PROCESS_MSGID, PONG, FINISHED };
2:
3: class Ping : public Process {
4: PID pong;
5:
6: void operator () () {
7: send(pong, PING);
8: switch (receive()) {
9: case PONG:
10: send(pong, FINISHED);
11: break;
12: }
13: }
14:
15: public:
16: Ping(const PID &_pong) : pong(_pong) {}
17: };
18:
19: class Pong : public Process {
20: void operator () () {
21: switch (receive()) {
22: case PING:
23: send(from(), PONG);
24: break;
25: case FINISHED:
26: return;
27: }
28: }
29: };
30:
31: int main(int argc, char **argv) {
32: PID pong = Process::spawn(new Pong());
33: PID ping = Process::spawn(new Ping(pong));
34: Process::wait(pong);
35: Process::wait(ping);
36: return 0;
37: }
While libprocess was initially constructed for implementing C++
applications, libprocess can be used from Python too! (See the README
file in the download for how to build the Python shared library). In
the example below, we are also using the pickle module to allow us to
do easy serialization of data between processes.
1: from process import Process, PROCESS_MSGID
2:
3: PING, PONG, FINISHED = range(PROCESS_MSGID, PROCESS_MSGID + 3)
4:
5: class Ping(Process):
6: def __init__(self, pong):
7: Process.__init__(self)
8: self.pong = pong
9:
10: def __call__(self):
11: data = pickle.dumps("hello world")
12: self.send(self.pong, PING, data, len(data))
13: self.send(self.pong, FINISHED)
14:
15:
16: class Pong(Process):
17: def __init__(self):
18: Process.__init__(self)
19:
20: def handlePING(self):
21: data, length = self.body()
22: print pickle.loads(data)
23: return True
24:
25: def handleFINISHED(self):
26: return False
27:
28: def __call__(self):
29: while {
30: PING: lambda: self.handlePING(),
31: FINISHED: lambda: self.handleFINISHED()
32: }[self.receive()]():
33: self.send(self._from(), PONG);
34:
35:
36: if __name__ == "__main__":
37: pong = Process.spawn(Pong())
38: ping = Process.spawn(Ping(pong))
39: Process.wait(ping)
40: Process.wait(pong)
You can make the serialization look more transparent too:
1: from process import Process, PROCESS_MSGID
2:
3: PING, PONG, FINISHED = range(PROCESS_MSGID, PROCESS_MSGID + 3)
4:
5: class PickledProcess(Process):
6: def __init__(self):
7: Process.__init__(self)
8:
9: def send(self, pid, msgid, *args):
10: data = pickle.dumps(args)
11: super(PickledProcess, self).send(pid, msgid, data, len(data))
12:
13: def body(self):
14: data, length = super(PickledProcess, self).body()
15: return pickle.loads(data)
16:
17:
18: class Ping(PickledProcess):
19: def __init__(self, pong):
20: Process.__init__(self)
21: self.pong = pong
22:
23: def __call__(self):
24: self.send(self.pong, PING, "hello world")
25: self.send(self.pong, FINISHED)
26:
27:
28: class Pong(PickledProcess):
29: def __init__(self):
30: Process.__init__(self)
31:
32: def handlePING(self):
33: print = self.body()
34: return True
35:
36: def handleFINISHED(self):
37: return False
38:
39: def __call__(self):
40: while {
41: PING: lambda: self.handlePING(),
42: FINISHED: lambda: self.handleFINISHED()
43: }[self.receive()]():
44: self.send(self._from(), PONG);
45:
46:
47: if __name__ == "__main__":
48: pong = Process.spawn(Pong())
49: ping = Process.spawn(Ping(pong))
50: Process.wait(ping)
51: Process.wait(pong)
Distributing your applicaiton is easy too ... just get the PIDs
correct and it doesn't matter what runs where!
In addition, libprocess is limited by the non-blocking I/O support provided by the underlying operating system. This means, unfortunately, that on most operating systems filesystem reads and writes will not be executed in a non-blocking way, even if that file is located in some network attached storage!
git clone git://scm.millennium.berkeley.edu/libprocess
This is a VERY ALPHA release that is currently only building on Linux (and probably Solaris, but that hasn't been tested as recently)! Please, please, please contact me if you run into any bugs (which you probably will), and I'll try and rectify them immediately. More importantly, let me know if you download the code so I can notify you when you should pull!