rpyc.Service 需要 10 秒来接收一个 150kB 的对象(在 localhost 上,没有 LAN 问题)
Posted
技术标签:
【中文标题】rpyc.Service 需要 10 秒来接收一个 150kB 的对象(在 localhost 上,没有 LAN 问题)【英文标题】:rpyc.Service takes 10 seconds to receive a 150kB object (on localhost, no LAN issue) 【发布时间】:2013-01-22 16:44:45 【问题描述】:我正在构建一个大的(腌制时为 150kB)虚拟字典,并在其上运行一个快速平稳运行的虚拟函数。
当通过 rpyc.Service 公开相同的功能时,即使我的客户端和服务器位于同一主机上,所用时间也会变为 10 秒(而不是 0.0009 秒)(这里的 LAN 延迟没有问题)。
知道为什么我的 150kB 对象从客户端传送到同一主机上的服务器需要这么长时间吗?
为什么即使输入对象还不“可用”,函数dummy.dummy()
也会被调用(如果是,那么在两个测试用例中花费在函数中的时间将是相同的)?
请参阅下面的我的 python (3.2) 代码。我测量了在 dummy.dummy(d) 中花费的时间。
-
案例1:dummy.dummy被客户端调用;执行时间 = 0.0009
案例2:dummy.dummy被称为rpyc服务;执行时间 = 10 秒
mini_service.py
import rpyc
from rpyc.utils.server import ThreadedServer
import dummy
class miniService(rpyc.Service):
def exposed_myfunc(self,d):
#Test case 2: call dummy.dummy from the service
dummy.dummy(d)
if __name__=='__main__':
t = ThreadedServer(miniService,protocol_config = "allow_public_attrs" : True, port = 19865)
t.start()
mini_client.py
import rpyc
import sys
import pickle
import dummy
def makedict(n):
d=x:x for x in range(n)
return d
if __name__ == "__main__":
d=makedict(20000)
print(sys.getsizeof(d)) #result = 393356
# output = open("C:\\rd\\non_mc_test_files\\mini.pkl",'wb') #117kB object for n=20k
# pickle.dump(d,output)
# output.close()
#RUN1 : dummy.dummy(d) out of rpyc takes 0.00099 seconds
# dummy.dummy(d)
#RUN2 : dummy.dummy(d) via RPYC on localhost takes 9.346 seconds
conn=rpyc.connect('localhost',19865,config="allow_pickle":True)
conn.root.myfunc(d)
print('Done.')
dummy.py
import time
def dummy(d):
start_ = time.time()
for key in d:
d[key]=0
print('Time spent in dummy in seconds: ' + str(time.time()-start_))
【问题讨论】:
您是否分析了访问单个密钥所花费的时间(即d[key] = 0
所花费的时间)?我相信 rpyc 会进行一些序列化并在您每次执行d[key] = 0
时发送一些消息,这显然会增加千倍所花费的时间[而不是单个 python 字节码,而是序列化 + 与其他进程的通信 + 获取结果,这是很多IO慢)。
好点。对于客户端,d[key]=0 迭代 10 次需要 0 秒。该服务平均需要 0.002 秒。是不是意味着对象的每次修改都与客户端同步?
是的。 0.002
对于单个操作来说太多了。一定是进程间的IO。如果你想让事情变得更快,你应该避免对远程对象进行微小的操作。
当我在服务器端收到对象时,我现在正在执行 copy.deepcopy,然后处理副本。这样,rpyc 就不必处理在客户端和服务器之间保持引用同步的问题。问题解决了。注意:看起来需要allow_picke=True。
【参考方案1】:
看起来性能损失来自 rpyc 为保持客户端和服务器之间的对象(通过引用传递)同步所做的工作。
我现在在我的应用程序中所做的是制作输入对象的深拷贝,然后处理该副本,从而模拟按值传递机制。
注意:深拷贝需要在协议配置参数中设置allow_picke=True
。
【讨论】:
以上是关于rpyc.Service 需要 10 秒来接收一个 150kB 的对象(在 localhost 上,没有 LAN 问题)的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC 怎么能花费超过 10 秒来加载(第一次)一个空白控制器?