easycluster:python的远程执行/集群模块

EasyCluster的Python项目详细描述


易簇
=========== < BR>
easycluster是python的远程执行/集群模块。 < BR>
可能的用途包括: < BR>
*计算(例如numpy、pyopencl)
*测试网络/SAN的协调自动化
*访问多个系统中的特定硬件(如GPU、视频采集/编码板) < BR><链接>

*[发布](https://pypi.python.org/pypi/easycluster)
*[开发](https://github.com/jspenguin/easycluster)
*[文档](http://pythonhosted.org/easycluster/) < BR>
要求
----
*cpython 2.6+或3.2+
*ssh支持在客户端需要一个"ssh"二进制文件,在服务器上需要一个"sshd" < BR>
功能
--
*函数和方法的透明调用
*透明处理异常
*用于并行调用一个函数的方便函数
多个远程系统
*自动支持线程
*使用共享hmac密钥保护的请求和响应
*通过ssh连接而不在服务器上安装任何东西(仅限linux/unix)
*跨平台兼容;在Linux/OSX上运行的主脚本可以连接
到运行在Windows上的服务器,反之亦然。 < BR>< BR>
安装
---- < BR>
easycluster使用setuptools进行安装。要安装,请运行: < BR>
python setup.py构建
sudo python setup.py安装 < BR>
如果您没有安装setuptools,将为您下载。 < BR>< BR>
工作原理
---- < BR>
easycluster的工作原理是让一个主脚本连接到一个或多个主脚本
运行ssh或群集服务的服务器。然后主人可以调用python
远程服务上的函数或发送要执行的代码。 < BR>
有关如何使用大多数功能的示例,请参见"easycluster\u demo.py"。 < BR>
自0.22.1版以来,ssh是连接到上的服务器的首选方法
除Windows以外的所有平台。使用ssh时,服务器不需要
easycluster已安装-它只需要有ssh和python 2.6、2.7或
>3.2。使用ssh时,应该使用ssh私钥和ssh代理,
否则ssh在连接时会提示输入密码。 < BR>
如果不想使用ssh,例如需要在windows上运行服务器
不想运行cygwin,需要生成共享的密钥
在客户端和服务器之间。此密钥用于验证请求,但是
不加密数据,因此只能在受信任的防火墙上使用
网络,不要在互联网上公开。如果要使用easycluster
远程地理区域的坐标系统,考虑使用VPN或ssh
隧道。easycluster服务在单个tcp端口上运行,因此大多数
隧道解决方案将起作用。 < BR>< BR>
连接到服务器
< BR>
使用easycluster最简单的方法是使用client.from\u spec: < BR>
>>rmt=client.from_spec('user@example.com')
>>>rmt=threadedclient.from_spec('user@example.com:rpython=python2.7') < BR>
连接规范如下: < BR>
[用户@]主机[:端口][:opt=val]… < BR>< BR>
"主机"可以是主机名、IPv4地址或括号中的IPv6地址。 < BR>
出于兼容性原因,仅当"user"字段存在时才使用ssh。如果
要在不指定用户名的情况下使用ssh,请将:ssh=yes作为选项传递。 < BR>
对于独立服务器,通过指定"kf"或"key"选项来确定密钥。 < BR>
如果指定了":compress=1",则为连接启用压缩。 < BR>
连接规范示例: < BR>
"user@example.com"使用ssh
"example.com:ssh=yes"使用不带用户名的ssh(让ssh选择) < BR>'example.com:ssh=/usr/local/bin/ssh'使用自定义ssh路径
非标准端口上的"用户@192.0.2.1:9999"IPv4地址
"用户@[2001:db8::2]"IPv6地址必须在括号中
"example.com:kf=secret.key"使用文件中的密钥连接到独立服务器
"example.com:9999:key=s3cret"直接使用带有非标准端口的密钥 < BR>
允许脚本用户指定远程
选项是使用"optparse": < BR>
文件:connect_example.py < BR>
导入系统
导入OptParse
导入EasyCluster < BR>
options=optparse.optionparser(description='做些事情')
easycluster.add_key_选项(选项)
opts,args=选项。parse_args()
默认键=easycluster.key从选项(opts)
遥控器=[]
对于args中的规范:
params=easycluster.parse_connection_spec(spec,default_key=default_key)
rmt=easycluster.client(**params)
远程追加(rmt) < BR>
此示例允许用户使用"-k"指定默认密钥(如果有多个
服务器使用相同的密钥),但允许用户在以下情况下指定单个密钥
必要: < BR>
python do_stuff.py-k common.key host1 host2 oddhost:kf=key_for_oddhost.key < BR>
您还可以指定要连接的其他TCP端口。如果你
要使用ssh隧道: < BR>
ssh主机1-n-f-l 11001:本地主机:11999
ssh主机2-n-f-l 11002:本地主机:11999
python do_stuff.py-k common.key本地主机:11001本地主机:11002 < BR>
主脚本可以多次连接到同一服务器。每个连接
创建一个具有干净环境的单独流程。大师也可以创造
使用"easycluster.server.spawn_local()"的"本地"实例,它启动一个新的
不必运行单独服务器的服务器进程。 < BR>< BR>
远程执行代码
- < BR>
远程执行代码最直接的方法是在
一个字符串,并调用"define_common()": < BR>
>>>>来自easycluster import*
>>gt;定义"公用"(''
…定义添加(A,B):
…返回A+B
…定义子值(A,B):
…返回-B
…'')
>>>key=读取密钥文件("secret.key")
>;>;rmt=客户端(键"localhost")
>>>RMT.附加值(3,4)
7
>>>RMT.子值(15,4)
11 < BR>
在传递给的代码块中定义的任何函数或类
可以在远程端调用define_common。您也可以在中调用函数
标准库模块中定义的类: < BR>
>;>;rmt.subprocess.call(['/bin/echo','hello'])
>;>; < BR>
此示例实际上不会向终端回显任何内容-`echo`被执行
在服务器上,因此如果在终端中打开服务器,您将看到它
在那里回响。 < BR>
您传递给define_common的代码块也在客户机上计算,因此
函数、类和类实例可以通过引用进行pickle并传递
在客户端和服务器之间来回切换。默认情况下,一个名为
创建"easycluster.remote_code"来存储定义。您可以导入
如果要在客户端和
服务器,或创建将通过
值: < BR>
>>>>来自easycluster.remote_code导入addvals,subvals
>>gt;附加值(1,2)
3
>;>; < BR>
您可以通过指定其他第二个参数来更改模块的名称
定义"公共"。记住,因为这段代码是在con中执行的文本
另一个模块,您将无法访问全局变量并导入
主脚本中的模块: < BR>
>>>导入操作系统
>>gt;定义"公用"(''
…DEHL():
…os.system('echo hello')
…'')

>;>>rmt.hello()
回溯(最近一次通话时间):

名称错误:未定义全局名称"os"
>;>; < BR>
您必须记住在您的
定义公共块。当然,您导入的库必须在
远程系统也-easycluster不会复制它们。 < BR>
例外情况
---- < BR>
如果远程代码引发异常,则将对异常进行pickle操作,并
在客户端上重新引发,以及堆栈跟踪。默认情况下,堆栈跟踪
将被打印到stderr,否则将丢失堆栈跟踪
在客户机上引发异常生成的异常只会到达代理
包装纸。如果不想打印异常,可以将"client"子类`
并重写"报告异常"。对于单个请求,还可以设置
"origexc"到"false"或"quiet"(请参阅下面关于并行执行的部分)。 < BR>
操作服务器上的对象
< BR>
默认情况下,如果在服务器上调用某个函数并返回一个值,则
将对值进行pickle,并在
客户。对于简单的值,比如字符串、整数、元组,
词典等,但许多对象不能或不应该被pickle;相反,
easycluster允许您将类标记为未pickle的"服务器对象",
但保留在服务器上并由客户端引用。 < BR>
在客户端上重建返回的数据结构时,任何"服务器"
对象被转换为"代理"对象。在此代理上调用方法
调用服务器上的相应方法。这些代理对象也可以是
作为参数传递给同一连接上的其他函数,并将
未序列化为服务器上的原始对象。 < BR>
>>gt;定义"公用"(''
…类testobject1(serverobject):
…定义初始值(自身值):
…self.val=值
…定义获取值(自身):
…返回self.val
…def newobj(自我):
…返回testobject1(self.val+1)

…定义获取对象值(LST):
…return[lst中obj的obj.val]
…'')
>;>;
>;>在调用define\u common后对每个连接调用此选项。
>>>rmt.更新定义()
>;>;
>>>obj1=rmt.testobject1(100)
>>>目标1
<;本地主机上OID 1的远程代理:11999>;
>>>目标1.getval() < > 100
>>>obj2=obj1.newobj()
>>>目标2
<;本地主机上OID 2的远程代理:11999>;
>>>目标2.getval()
101
>>>rmt.获取对象值[obj1,obj2]
[100101]
>;>; < BR>
类可以指示它们应该被代理而不是被复制
从"serverobject"继承。不知道easycluster的现有类
可以通过调用"make_server_class"在服务器上注册。 < BR>
类可以通过两种方式指定要导出的方法和属性: < BR>
*指定"导出方法"、"导出属性"或"导出属性缓存"。班
从"serverobject"继承但未指定代理类的
第一次引用时动态创建的。服务器将
检查类以确定哪些方法属性应该是
已导出。 < BR>
*如果类具有名为"export_methods"的类属性,则代理
类将只有这些方法的包装器。 < BR>
*如果未定义"export_methods"(默认值),或特殊值"@auto"`
在导出的方法名列表中,然后将检查该类,
所有定义的方法都将自动添加到列表中。 < BR>
*export_attrs类属性的工作方式相同:如果定义了它,
将在代理对象上为每个
属性。如果未定义"export_attrs",或"auto"包含在
导出属性,然后在代理上定义一个特殊的"getattr"
将属性访问转发到服务器。 < BR>
*如果您知道某个属性包含的数据不会在
对象的生存期,可以将其放入"导出属性缓存"中。客户
将在第一次访问属性时缓存该属性的值,并且
将不再访问它。 < BR>
*直接定义代理类。这是最灵活的出口方式
方法和属性。这不仅允许您定义代理方法和
属性,但允许您: < BR>
*在客户机上实现简单方法。例如,大多数迭代器只是
从"iter"返回"self"。实际上,easycluster提供了一个代理类
可以从selfiterproxy继承。 < BR>
*使代理对象从其他类继承,以便
`isinstance(prox,clas)`返回'true'。 < BR>
两种方法的示例: < BR>
>>gt;定义"公用"(''
…类testobject2(testobject1):
…导出方法=('getval',)
…导出属性=('val',)

…类TestObject3Proxy(远程代理):
…代理方法=('getval',)
…代理属性=('val',)

…类testobject3(testobject1):
…代理类=testobject3proxy
…'')
>;>;
>>>rmt.更新定义()
>>>obj2=rmt.testobject2(200)
>>>目标2.val
200
>>>目标2.getval()
200
>>gt;obj2.不存在方法()
回溯(最近一次通话时间):
文件"<;stdin>;",第1行,在<;模块>;
attributeerror:"dynamic_proxy_getval_val"对象没有"non_existant_method"属性
>;>; < BR>
>>gt;定义"公用"(''
…'')
>>>rmt.更新定义()
>>>obj3=rmt.testobject3(300)
>>>>类型(OBJ3)
<;类"easycluster\u code.testobject3proxy">;
>>>目标3.val
300 < BR>
如果有内置类或库模块中的类
将其视为"服务器对象",可以在
定义公共块: < BR>
>>gt;定义"公用"(''
…导入数组
…使服务器类(array.array)
…'')
>>>rmt.更新定义()
>>>rmt_array=rmt.array.array('b',1234) < BR>
您可以传递"export-attrs"、"export-attrs"、"export-attrs-cache"和
"proxy_class"到"make_server_class";它们的含义与
服务器对象。 < BR>
还有一个名为"make_singleton"的函数,其行为类似于
"make_server_class",除非它在类的单个实例上操作;如果
返回实例,它将被代理,但同一类的其他实例
将被腌制。 < BR>
并行执行
----- < BR>
通常,集群意味着您希望在多个上并行执行代码
系统。默认情况下,调用远程代码会暂停主脚本的执行
执行远程代码时。但是,有几种方法可以执行
并行远程代码。 < BR>
最简单的方法是使用非阻塞响应: < BR>
>;>;rmt2=客户机(键,"其他主机")
>>>r1=RMT.添加值(5,8,非阻塞=真)
>>>r2=rmt2.添加值(14,18,非阻塞=真)
>>>r1.等待()
13
>>>r2.等待()
32
>;>; < BR>
将"nonblocking=true"传递给任何代理方法都会导致它立即返回
具有"wait()"方法的特殊"非阻塞响应"对象。"WAITE()"
方法等待代码在远程服务器上完成执行,然后
返回响应值。如果远程端引发异常,"wait()"`
将引发相同的异常(除非通过"origexc"--请参见下文)。 < BR>
您还可以使用"eval_multi"、"call_multi"和
"call_method_multi"在多个系统上并行调用同一个函数: < BR>
>;>;调用多个([rmt,rmt2],'addvals',2,3)
[5,5]
>;>; < BR>
此函数调用多个系统上的特定函数,等待
响应,然后返回其响应的列表。 < BR>
除了"nonblocking"之外,还有其他常见的关键字参数可以是
传递给远程调用: < BR>
*`oncomplete`-如果指定了此选项,则远程调用将返回
立即,并在远程调用完成时调用此函数。这个
可以是被称为"func(response)"的函数,也可以是元组
属于`(func,arg1,arg2,…)’,称为`func(response,arg1,
arg2,…)`。如果您使用的是标准的"client"类,则完成函数
在客户端上调用"read_response()"之前不会调用
对象,或对与
客户。如果您使用的是"threadedclient",则完成函数从
从服务器读取响应的线程。 < BR>
*`onerror`-与oncomplete相同,但使用'remoteexception'调用`
当远程调用引发
例外。如果指定了"onComplete",但未指定"onerror",则
"onComplete"函数在这两种情况下都被调用。 < BR>
*`threadid`-指定要在服务器上运行的线程的任意整数
中的请求。如果未指定,将使用当前默认值。这个
可以通过在客户端上调用"set_default_thread()"来更改默认值
对象。如果服务器上不存在指定的线程,则
已创建。如果threadid是特殊常量"easycluster.single",则
在服务器上为此请求创建线程,然后退出。 < BR>
*`origexc`-如果'true`(默认),并且请求引发异常,则它将
将远程堆栈跟踪打印到屏幕并提升原始
例外。如果为"false",则会引发"remoteexception"。如果是
值"quiet",则在没有堆栈的情况下引发原始异常
正在打印跟踪。` remoteexception`实例有两个属性:
"orig",原始异常;和"text",服务器上的堆栈跟踪。 < BR>
可以使用非阻塞方式在同一服务器上启动多个线程
带有"threadid"的响应: < BR>
>>>r1=rmt.addvals(101,102,nonblocking=true,threadid=1)
>>>r2=rmt.addvals(222333,nonblocking=true,threadid=2)
>>>r3=rmt.addvals(555888,nonblocking=true,threadid=3)
>;>;[r1.wait(),r2.wait(),r3.wait()]
[2035551443] < BR>< BR>
使用threadedclient
---- < BR>
如果主脚本已经是多线程的,则可以使用"threadedclient"`
为您自动管理服务器线程。 < BR>
"threadedclient"类启动一个单独的线程,从
服务器。因此,只要
调用返回,线程主动监视服务器以确保它
没有下楼或被锁起来。 < BR>
`threadedclient`将检测您是否从单独的线程调用远程函数
在主脚本中,并将在服务器上启动相应的线程
处理您的请求: < BR>
>>>导入线程
>>>tc1=线程客户端(键"host1")
>;>;tc2=线程客户端(键"host2")
>;>;
>>>定义客户机线程(ID,A,B):
…"打印"线程%d:正在启动%id"
…val1=tc1.附加值(a,b)
…print'线程%d:tc1返回%r'%(id,val1)
…val2=tc2.添加值(a,b)
…print'线程%d:tc2返回%r'%(id,val2)
…"打印"线程%d:已完成%id"

>;>>定义运行线程():
…T1=线程。线程(目标=客户端线程,参数=(1200,500))
…T2=线程。线程(目标=客户端线程,参数=(230600))
…T1.start();T2.start()
…t1.join();t2.join()

>>>运行线程()
线程1:启动
线程2:启动
线程1:tc1返回700
线程2:tc1返回900
线程1:tc2返回700
线程2:tc2返回900
螺纹1:完成
螺纹2:完成
>;>; < BR>
一旦主脚本中的线程退出,"threadedclient"将检测到它并
停止服务器上相应的线程。 < BR>< BR>
启动独立服务器
-------- < BR>
在posix系统(linux、bsd、solaris)上,名为"easycluster"的命令应该是
安装在`/usr/local/bin`。在windows上,安装了主入口点
在"%python%\scripts\easycluster.exe"下。使用Python2.7和3.2,您还可以
运行"python-m easycluster"。 < BR>
在运行服务器之前,应该创建一个秘密的hmac密钥文件。两个
服务器和客户端需要此密钥文件才能进行通信: < BR>
easycluster-g secret.key < BR>
这将创建一个名为"secret.key"的新文件,该文件只能由
创建它的用户。然后可以使用以下命令运行服务器: < BR>
easycluster-s-k secret.key < BR>
如果不想看到每个远程呼叫都被记录,请运行: < BR>
easycluster-s-k secret.key-c静止服务器 < BR>< BR>
启动时将easycluster独立服务器作为服务运行
-- < BR>
在Windows上启动时,您可以让EasyCluster服务自动启动,
solaris和linux(redhat、debian、ubuntu和suse已经过测试): < BR>
easycluster—安装 < BR>
这将向系统注册服务,该服务将在下一个 靴子。您可以使用"easycluster--uninstall"注销它。一旦服务完成
注册后,您可以使用"easycluster--start"和
`easycluster--停止` < BR>

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java如何在linux中使用命令行编译eclipse项目?   java从excel单元格值读取和提取文件名   mongodb游标异常Java   如何在Java中从randDouble中随机获得1100之间的值?   java使用bean引用从SpringXML配置迁移到@configuration(Servlet3.0)会导致BeanNotOfRequiredTypeException   java我是否正确地实现了deltatime?   java将CSV内容附加到邮件中   数据库中具有重复值的java Hibernate update语句   c#如何使用Java在Windows上创建虚拟磁盘(信件、共享等)?   java使用InsertionSort算法对包含空元素的字符串数组进行排序   使用Java正则表达式提取html中的文本   java如何在安卓中使用导入包中的类   检查字符的java规则   不带列名的java DefaultTableModel   java Nillable=false在apache cxf中不起作用   java DecimalFormat无法处理数学问题。圆周率   当用户再次登录时,数据从Firebase数据库中删除   java Android Dropbox API v2使用访问令牌自动访问   从Mockito参数captor捕获时,java函数接口不可序列化