AppEngine Query.fetch_async不是非常异步?

 手机用户2602921931 发布于 2022-12-21 17:47

我正在尝试通过使用query.fetch_async()异步运行多个子查询来减少AppEngine查询的执行时间.但是,与串行运行查询相比,增益似乎很小.

下面是一些说明问题的最小示例代码(在Python中) - 首先是异步运行的函数:

def run_parallel(self, repeats):
    start = datetime.utcnow()

    futures = []
    for i in xrange(0, repeats):
        q = User.query()
        f = q.fetch_async(300, keys_only=True)
        futures.append(f)

    while futures:
        f = ndb.Future.wait_any(futures)
        futures.remove(f)
        results = f.get_result()
        delta_secs = (datetime.utcnow() - start).total_seconds()
        self.response.out.write("Got %d results, delta_sec: %f
\n" %(len(results), delta_secs))

然后是相应串行运行的函数:

def run_serial(self, repeats):
    start = datetime.utcnow()
    for i in xrange(0, repeats):
        q = User.query()
        results = q.fetch(300, keys_only=True)
        delta_secs = (datetime.utcnow() - start).total_seconds()
        self.response.out.write("Got %d results, delta_sec: %f
\n" %(len(results), delta_secs))

运行这两个函数的输出各10次(不在dev服务器上),即以下调用:

run_parallel(10)
run_serial(10)

如下:

运行并行查询...
得到300结果,delta_sec:0.401090
得到300结果,delta_sec:0.501700
得到300结果,delta_sec:0.596110
得到300结果,delta_sec:0.686120
得到300结果,delta_sec:0.709220
得到300结果,delta_sec:0.792070
得到了300结果,delta_sec:0.816500
得到300结果,delta_sec:0.904360
得到300结果,delta_sec:0.993600
得到300结果,delta_sec:1.017320

运行串行查询...
得到300结果,delta_sec:0.114950
得到300结果,delta_sec:0.269010
得到300结果, delta_sec:0.370590
得到300结果,delta_sec:0.472090
得到300结果,delta_sec:0.575130
得到300结果,delta_sec:0.678900
得到300结果,delta_sec:0.782540
得到300结果,delta_sec:0.883960
得到300结果,delta_sec:0.986370
得到300结果,delta_sec :1.086500

因此,并行和串行版本大约需要大约相同的时间,大约1秒钟.Appstat如下,其中前10个查询是并行查询,后面10个查询是串行查询:

在此输入图像描述

从这些统计数据看,10个第一个查询确实并行运行,但与单个串行查询相比,每个查询都花费了不成比例的时间.看起来他们可能会以某种方式阻止,等待彼此完成.

所以我的问题:我的代码运行异步查询有什么问题吗?或者AppEngine上异步查询的效率是否存在固有的局限性?

我想知道这种行为是否可能是由下列之一造成的:

    在同一实体类型上运行异步查询.但是,使用多个不同实体类型的类似示例显示了类似的结果.

    运行相同的查询,以某种方式锁定索引的部分.但是,每个查询不同(返回不相交的结果集)的类似示例会产生类似的结果.

所以,我有点失落.任何建议将不胜感激.

更新1

按照Bruyere的建议我尝试使用db而不是ndb,我尝试交换并行和串行版本的顺序.结果是一样的.

更新2

这是一个涉及同一问题的相关帖子; 仍然没有答案为什么并行查询是如此低效:

从数据存储区查询大量ndb实体的最佳实践

更新3

使用Java SDK的相应代码非常整齐地并行化.以下是Java appstats:

在此输入图像描述

确切地说,这个Java实现是显式多线程的,在不同的线程中运行查询; 这是必要的,因为与AppEngine文档声称的相反,使用查询迭代器实际上并不会导致查询并行执行.

我试图在Python版本中使用带有同步查询调用的显式多线程,但结果与原始Python版本相同.

Java版本按预期执行的事实意味着可怜的Python异步性能不是由AppEngine CPU瓶颈引起的.

我能想到的唯一替代解释是Python的Global Interpreter Lock导致颠簸.这一点得到以下事实的支持:减少GIL检查间隔(使用sys.setcheckinterval)会加剧糟糕的异步性能.

这是令人惊讶的:鉴于查询是IO绑定的,GIL应该不会产生如此严重的影响.我推测也许RPC输入缓冲区足够小,以至于异步调用在检索结果时经常恢复,这可能会导致GIL颠簸.我已经看过Python AppEngine库代码,但是低级RPC调用是由_apphosting_runtime ___ python__apiproxy.MakeCall()创建的,它似乎是封闭源代码.

唉,我的结论是Python AppEngine运行时不适合我需要的那种并行查询,除了转移到Java运行库之外别无其他选择.我真的想避免这种情况,所以我真的希望我错了,错过了一些明显的东西.任何建议或指示将不胜感激.

谢谢!

撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有