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 问题)的主要内容,如果未能解决你的问题,请参考以下文章

如何在 RPyC 中获取连接到服务器的客户端列表?

ASP.NET MVC 怎么能花费超过 10 秒来加载(第一次)一个空白控制器?

更新查询需要 2 秒来更新表

Spark 需要 0.5 秒来平均 100 个数字

JDBC ResultSet 方法 next() 需要 30 秒来获取 12000 行

Grails:部署时间非常慢。 'Resolving Dependencies...' 需要 10 多秒