Pyro4 分布式计算简单示例

2018-08-01  本文已影响0人  csdongxian

本文的例子来自 Pyro4 官网的 tutorial。这年头,Python的包各种强大,通过Pyro可以轻松进行分布式计算。具体说来,即使被调用方法的对象在远程服务器,Pyro 都可以让我们轻松调用。

+----------+                         +----------+
| server A |                         | server B |
|          |       < network >       |          |
| Python   |                         |   Python |
| OBJECT ----------foo.invoke()--------> OBJECT |
|          |                         |     foo  |
+----------+                         +----------+

概念

示例

1. 本地实现

首先在本地实现代码:有一个Warehouse类,它的实例表示某个具体的仓库,负责保管物品;还有一个Person类,它的实例表示某个人,他可以去仓库存取物品。
在这个例子中,Janet 和 Henry要去本地的仓库存取物品。既然仓库在本地,当然就很方便了。

class Warehouse(object):
    def __init__(self):
        self.contents = ["chair", "bike", "flashlight", "laptop", "couch"]

    def list_contents(self):
        return self.contents

    def take(self, name, item):
        self.contents.remove(item)
        print("{0} took the {1}.".format(name, item))

    def store(self, name, item):
        self.contents.append(item)
        print("{0} stored the {1}.".format(name, item))
import sys

class Person(object):
    def __init__(self, name):
        self.name = name

    def visit(self, warehouse):
        print("This is {0}.".format(self.name))
        self.deposit(warehouse)
        self.retrieve(warehouse)
        print("Thank you, come again!")

    def deposit(self, warehouse):
        print("The warehouse contains:", warehouse.list_contents())
        item = input("Type a thing you want to store (or empty): ").strip()
        if item:
            warehouse.store(self.name, item)

    def retrieve(self, warehouse):
        print("The warehouse contains:", warehouse.list_contents())
        item = input("Type something you want to take (or empty): ").strip()
        if item:
            warehouse.take(self.name, item)

最后写一个脚本来运行,如下:

# This is the code that runs this example.
from warehouse import Warehouse
from person import Person

warehouse = Warehouse()
janet = Person("Janet")
henry = Person("Henry")
janet.visit(warehouse)
henry.visit(warehouse)

运行脚本,得到输出如下:

$ python visit.py
This is Janet.
The warehouse contains: ['chair', 'bike', 'flashlight', 'laptop', 'couch']
Type a thing you want to store (or empty): television   # typed in
Janet stored the television.
The warehouse contains: ['chair', 'bike', 'flashlight', 'laptop', 'couch', >>>  'television']
Type something you want to take (or empty): couch    # <-- typed in
Janet took the couch.
Thank you, come again!
This is Henry.
The warehouse contains: ['chair', 'bike', 'flashlight', 'laptop', 'television']
Type a thing you want to store (or empty): bricks   # <-- typed in
Henry stored the bricks.
The warehouse contains: ['chair', 'bike', 'flashlight', 'laptop', 'television', 'bricks']
Type something you want to take (or empty): bike   # <-- typed in
Henry took the bike.
Thank you, come again!

2. 分布式实现

但是顾客总比商家多,总有些小地方没有被商家覆盖。这该如何是好?
到分布式这个例子上,Janet和Henry两人在A地,他们要去仓库存取物品,但仓库主体都在B地。有Pyro在,就不用他们大老远跑了。首先仓库要拿到异地办理的资质(成为Pyro对象),然后在A地开一个门面(代理)。Jenet和Henry两人通过门面,就可以存取物品了。门面会把相应物品打包装箱(序列化),然后运到B地,再卸车拆包(反序列化)。仓库运营方(Pyro守护进程)会按要存入物品,再将两人要取的物品找出,装箱打包运到A地,再装卸取件。

import Pyro4

@Pyro4.expose
@Pyro4.behavior(instance_mode="single")
class Warehouse(object):
    def __init__(self):
        self.contents = ["chair", "bike", "flashlight", "laptop", "couch"]

    def list_contents(self):
        return self.contents

    def take(self, name, item):
        self.contents.remove(item)
        print("{0} took the {1}.".format(name, item))

    def store(self, name, item):
        self.contents.append(item)
        print("{0} stored the {1}.".format(name, item))

def main():
    Pyro4.Daemon.serveSimple(
            {
                Warehouse: "example.warehouse"
            },
            ns = False)

if __name__=="__main__":
    main()

首先在命令行中运行这部分代码,如下:

$ python warehouse.py
Object <__main__.Warehouse object at 0x025F4FF0>:
    uri = PYRO:example.warehouse@localhost:51279
Pyro daemon running.

这部分代码中的 @Pyro4.expose 表示这个类可以进行远程操作,就是仓库要拿到异地办理的执照。因为这里是将一个类注册为Pyro对象,所以要添加@Pyro4.behaviorinstance_mode="single"表示实例被创建后需要负责之后所有的方法调用,参考官方文档
最后使用main方法,将Warehouse类这个Pyro对象登记到了一个守护进程。仓库有公司进行运营,正式开业啦。运行得到的uri,就是仓库的地址啦,后面需要通过这个地址来找它。
函数Person类的代码无需修改。最后来看调用的脚本。

# This is the code that visits the warehouse.
import sys
import Pyro4
from person import Person

if sys.version_info<(3,0):
    input = raw_input

uri = input("Enter the uri of the warehouse: ").strip()
warehouse = Pyro4.Proxy(uri)
janet = Person("Janet")
henry = Person("Henry")
janet.visit(warehouse)
henry.visit(warehouse)

通过warehouse = Pyro4.Proxy(uri),我们得到了Warehouse实例的代理。Pyro4自动创建了对应的实例,并负责后面的调用。就是说,B地仓库在A地有门面了,并由该门面承接A地的业务。
大致做个示意图,见图1。可以看到,在Pyro的帮助下,在计算机A上可以轻松调用计算机B上的对象,只要实现将B上的对象进行一些操作(注册为Pyro对象,登记到守护进程),并把B上对象的uri交给A,并在A上直接把代理当做对象进行调用即可。

图1. Pyro4 图示。除Pyro外,其他红色字体就是前文提到的一些概念。
上一篇下一篇

猜你喜欢

热点阅读