自从2010年很多大公司开始制作自己的自动化工厂之后,很多自动化不再只是简单的写个脚本人工执行或者说只是适用一个项目的自动化需求.基本上都是需求分布式的
自动化测试和适合不同的项目.在负责调度的过程中,我用过TCL脚本的原生socket和
Java的原生socket进行做分布式,但是这个很考验一个工程师的编写多线程以及分布式的编写能力,所以出现过我离开项目组后,后来人因为socket不熟不敢优化或者2次开发这块.所以后来我在研究把这一块寻找出已经封装好的模块进行适用,这里介绍的是python的rpyc.
python的rpyc其实是用于远程调用客户端的方法的.可以这么理解,就是封装好的非阻塞的分布式socket.我们先看例子.
import time
from rpyc import Service
from rpyc.utils.server import ThreadedServer
class TimeService( Service ):
def exposed_get_time( self ):
return time.ctime() # time模块中的一个内置方法
def exposed_sum( self, a, b ):
return a + b
def exposed_get_list( self ):
return [1,2,3]
s = ThreadedServer( TimeService, port=12233, auto_register=False )
s.start()
Client端的代码client.py
# coding: gbk
import rpyc
c = rpyc.connect( 'localhost', 12233 ) # 首先要连接服务器
print c.root.get_time() # 调用服务器端的方法
sum = c.root.sum( 1, 2 ) # 调用服务器端的方法
print sum
lst = c.root.get_list()
print lst
c.close()
先不急与看rpyc的源代码,从他引用的模块中我们可以得到一些信息:
from rpyc import Service
from rpyc.utils.server import ThreadedServer
这里引用了SocketService作为它服务器继承的父类, ThreadedServer这个多线程的模块,就是说在rpyc使用的过程中是用到socket接受到信息,然后启动一条线程专门管理这个信息的.这里很符合我们的需求了.只要我们把自动化的任务下发下去,只要多台接受的服务器在线就能够舒服的发送下去.
我带着这个思维查看了下源代码的文件,我发现它是通过dom的包去封装xml协议的,不是我想象中的etree包,可能他有他的理由不用etree,这个不影响,不过在我预料当中的是它果然用到了工厂函数的方式实现远程调用:
def _rpyc_getattr(self, name):
if name.startswith("exposed_"):
name = name
else:
name = "exposed_" + name
return getattr(self, name)
其实跟我以前写自动化调度一样,采取的就是多线程,把消息的名字当作函数名,以字符串方式调用.此时我更关注的是close的方式.很多自动化复杂的情况下,什么时候close和谁负责close是个头痛的事情,我测试了下,我不加close走完一个函数后它的线程会自动关闭.因为我们调度很少会动则上千个线程,所以我就很放心的把close交给rpyc自动回收去做.
剩下最麻烦的来了,就是发送端发送消息过去其实大多时候不用等接收端做完事情后才结束,而rpyc需要等待,但是我们循环下发任务是基本上不会去等待的.所以我这边做了个实验,在远程函数中本来做的事情重新起个线程,也是工厂模式去调用这个函数.此时的基本架构为.
rpyc发送端与接收端做常链接,发送消息给接收端,接收端把消息的名字丢进线程中,在线程中寻找符合的函数执行,要返回执行结果的时候还是需要重新建立rpyc链接,此时的角色就反过来了.
所以最后的基本思路是,按照很多网络开发的方式,每个PC机都用接受端,用单双工的方式运作,发独立发,收独立收.
假如用别的语言去编写也是这个思路,例如c++和java都有主流封装好的socket包,稍微2次开发也可以做到这个效果.