免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3189 | 回复: 0
打印 上一主题 下一主题

[其他] An Erlang Port in Python [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-07-23 00:55 |只看该作者 |倒序浏览

Recipe 534162: An Erlang Port in Python
   
Erlang has two built-in interoperability mechanisms. One is
distributed Erlang nodes and the other one is ports.
Ports provide the basic Erlang mechanism for communication with the
external world. They provide a byte-oriented interface to an external
program. When a port has been created, Erlang can communicate with it
by sending and receiving lists of bytes. This recipe cooks an Erlang
port in python. Making it easy for Erlang to instantiate and use python
objects. Like most simple port implementations it uses an external
python program and lets Erlang communicate via standard input and write
to standard output. Theoretically, the external program could be
written in any programming language. This recipe is pretty abstract and
you will have to implement your own encode and decoding scheme.
  
   
      
        
        Python
      
      
        1
  2
  3
  4
  5
  6
  7
  8
  9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114import sys, os, struct, traceback
from cStringIO import StringIO
   
class ErlangPort(object):
    PACK = '!h'
    def __init__(self):
        self._in = sys.stdin
        self._out = sys.stdout
        
    def recv(self):
        buf = self._in.read(2)
        if len(buf) ==2:
            (sz,) = struct.unpack(self.PACK, buf)
            return self._in.read(sz)
        
    def send(self, what):
        sz = len(what)
        buf = struct.pack(self.PACK, sz)
        self._out.write(buf)
        return self._out.write(what)
    def run(self):
        buf = self.recv()
        while buf:
            try:
                result = self.process(buf)
            except:
                result = traceback.format_exc()
            self.send(result)
            buf = self.recv()
class ErlangPortTest(ErlangPort):
    cmds = (0,lambda x: x+2, lambda x: x*2)
    def process(self, message):
        fn,arg = struct.unpack('!BB', message)
        res = self.cmds[fn](arg)
        return struct.pack('!B', res)
class ErlangPyTest(ErlangPortTest):
    class SandBox:
        def process(self, message):
            exec message
    sandbox = SandBox()
    def process(self, code):
        try:
            realout = sys.stdout
            sys.stdout = StringIO()
            self.sandbox.process(code)
            result = sys.stdout.getvalue()
        finally:
            if sys.stdout: sys.stdout.close()
            if realout: sys.stdout = realout
        return result
            
if __name__ =='__main__':
    import sys
    try:
        command = sys.argv[1]
        if command == 'PortTest':
            ErlangPortTest().run()
        elif command =='pytest':
            ErlangPyTest().run()
    except IndexError:
        print """
Usage:
First of all see the c Port section in the Erlang guide.
http://www.erlang.org/doc/tutorial/c_port.html#4
1. Start Erlang and compile the Erlang user guide example code:
http://www.erlang.org/doc/tutorial/complex1.erl
unix> erl
Erlang (BEAM) emulator version 4.9.1.2
Eshell V4.9.1.2 (abort with ^G)
1> c(complex1).
{ok,complex1}
   
3. Run the example.
2> complex1:start("python -u port.py PortTest").
3> complex1:foo(3).
4
4> complex1:bar(5).
10
5> complex1:stop().
stop
   
For more fun try.
6> c("c:\\tg\\python.erl").
:/tg/python.erl:42: Warning: variable 'Reason' is unused
{ok,python}
7> python:start("c:\\python25\\python.exe -u c:\\tg\\port.py pytest").
8> python:exec("import os")
9> python:exec("self.x = os.environ['PATH']").
* 2: syntax error before: python **
10> python:exec("import os").                  
[]
11> python:exec("self.x = os.environ['PATH']").
[]
12> python:exec("print self.x").
"H:\\PROGRA~1\\ERL55~1.5\\ERTS-5~1.5\\bin;H:\\PROGRA~1\\ERL55~1.5\\bin
m Files\\ActivePositionManager\\;C:\\WINNT\\system32;C:\\WINNT;C:\\WI
32\\Wbem;"
"""
      
   
  
  
   
      
      Discussion
      
      
      
First of all see the c Port section in the Erlang guide.
http://www.erlang.org/doc/tutorial/c_port.html#4
.
Erlang
is a great language for distributed programming especially if you use
the OPT frame work, but python is nicer to program in. This class is my
first of many Erlang/Python utility classes that will let me program in
Python distributed nodes and yet manage them with Erlang code.
ErlangPort is the main base class in this recipe. For most cases all
you will have to do is override process to return a string or a struct
representation in network safe mode. Also remember to run python with
the -u (unbuffered) flag set.
ErlangPortTest is just a pythonesque port of the c example given in the Erlang guide. You can find the  Erlang example at
http://www.erlang.org/doc/tutorial/complex1.erl
ErlangPyTest lets Erlang execute python code block by block. In this
class I use a letter envelop idiom (Sandbox) to save Erlang form
clobbering the port object. Be careful how you use it!
For This use python.erl
-module(python).
-export([start/1, stop/0, init/1]).
-export([exec/1]).
start(ExtPrg) ->
    spawn(?MODULE, init, [ExtPrg]).
stop() ->
    python ! stop.
exec(X) ->
    call_port(X).
call_port(Msg) ->
    python ! {call, self(), Msg},
    receive
    {python, Result} ->
        Result
    end.
init(ExtPrg) ->
    register(python, self()),
    process_flag(trap_exit, true),
    Port = open_port({spawn, ExtPrg}, [{packet, 2}]),
    loop(Port).
loop(Port) ->
    receive
    {call, Caller, Msg} ->
        Port ! {self(), {command, Msg}},
        receive
        {Port, {data, Data}} ->
            Caller ! {python, Data}
        end,
        loop(Port);
    stop ->
        Port ! {self(), close},
        receive
        {Port, closed} ->
            exit(normal)
        end;
    {'EXIT', Port, Reason} ->
        exit(port_terminated)
    end.
      
   
  
  
Sign in
to comment
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/16651/showart_2004039.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP