Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading Google数据存储中带游标的多线程处理_Multithreading_Google App Engine_Google Cloud Datastore_Cursors - Fatal编程技术网

Multithreading Google数据存储中带游标的多线程处理

Multithreading Google数据存储中带游标的多线程处理,multithreading,google-app-engine,google-cloud-datastore,cursors,Multithreading,Google App Engine,Google Cloud Datastore,Cursors,我想从Google数据存储加载大量数据 因此,步骤1:我运行查询(使用keysOnly=true)并循环遍历游标,以便每个游标都指向包含600个对象的页面的开头。我将游标存储在局部变量中 步骤2:我为每个游标派生一个线程,在每个线程中加载和处理600个对象 这不是使用游标的通常方式 然而,在我看来这是正确的。步骤1和步骤2中的实际查询字符串是相同的。这类似于通常的无状态web用例,用户可以请求下一页、返回页,然后重新加载上一页;游标不需要直接来自上一个游标查询的结果 我不想为了并行处理给定游标查

我想从Google数据存储加载大量数据

因此,步骤1:我运行查询(使用keysOnly=true)并循环遍历游标,以便每个游标都指向包含600个对象的页面的开头。我将游标存储在局部变量中

步骤2:我为每个游标派生一个线程,在每个线程中加载和处理600个对象

这不是使用游标的通常方式

然而,在我看来这是正确的。步骤1和步骤2中的实际查询字符串是相同的。这类似于通常的无状态web用例,用户可以请求下一页、返回页,然后重新加载上一页;游标不需要直接来自上一个游标查询的结果

我不想为了并行处理给定游标查询中加载的对象而依次遍历游标,然后派生线程,因为我想并行处理来自DB的实际IO密集型查询


我得到了一些不一致的结果,似乎涉及遗漏的页面和重复加载的对象。这是多线程从Google数据存储加载大量数据的正确方法吗?如果不是,那是什么?

我会推荐一种不同的方法。只运行一个循环遍历所有实体的查询。它发生得非常快(不要忘记将批量大小设置为500,默认值仅为10)。如果查询很大,您可能仍然需要使用游标

对于每个实体,使用任务API创建一个任务,并将其添加到任务队列中。这些任务可以并行执行。您可以设置队列上的所有参数


使用这种方法,您不必担心线程,您可以将任务设置为在失败时自动重试,等等。我发现这是应用程序引擎吸引力的一个非常重要的部分-只编写您自己的逻辑,让应用程序引擎担心执行部分。

我建议使用另一种方法。只运行一个循环遍历所有实体的查询。它发生得非常快(不要忘记将批量大小设置为500,默认值仅为10)。如果查询很大,您可能仍然需要使用游标

对于每个实体,使用任务API创建一个任务,并将其添加到任务队列中。这些任务可以并行执行。您可以设置队列上的所有参数


使用这种方法,您不必担心线程,您可以将任务设置为在失败时自动重试,等等。我发现这是应用程序引擎吸引力的一个非常重要的部分-只编写您自己的逻辑,让应用程序引擎担心执行部分。

根据您的操作,您有几个选项:

  • 如果您有大量数据,请使用带有任务队列的“扇出”模型。在该模型中,任务队列作业加载一段数据,对其进行处理并存储结果,并可能触发更多的处理作业。Taskqueue节流允许您控制吞吐量/持续时间/成本,还可以处理失败/重试。此模型的一个优点是,您可以通过手动插入URL来测试和重新运行段,并在管理面板中查看进度

  • 使用GAE MapReduce-

  • 在单个进程中,如果您有少量数据。缺点是请求截止时间(60秒、10米或24小时-取决于服务器和请求的类型)。回想一下,数据存储操作是异步的,所以您可以在单个线程中并行运行请求,这可以简化代码。在它们变成阻塞之前,有多少是(我相信)由appengine-web.xml或app.yaml中的
    max并发请求控制的。如果您的请求可能会失败,并且无法恢复,那么这可能会非常昂贵


  • 根据您所做的工作,您有几个选择:

  • 如果您有大量数据,请使用带有任务队列的“扇出”模型。在该模型中,任务队列作业加载一段数据,对其进行处理并存储结果,并可能触发更多的处理作业。Taskqueue节流允许您控制吞吐量/持续时间/成本,还可以处理失败/重试。此模型的一个优点是,您可以通过手动插入URL来测试和重新运行段,并在管理面板中查看进度

  • 使用GAE MapReduce-

  • 在单个进程中,如果您有少量数据。缺点是请求截止时间(60秒、10米或24小时-取决于服务器和请求的类型)。回想一下,数据存储操作是异步的,所以您可以在单个线程中并行运行请求,这可以简化代码。在它们变成阻塞之前,有多少是(我相信)由appengine-web.xml或app.yaml中的
    max并发请求控制的。如果您的请求可能会失败,并且无法恢复,那么这可能会非常昂贵


  • 埃德·戴维森是一名谷歌工程师,负责谷歌数据存储客户端API。他提供了问题的根本原因和建议的解决方案

    他说:

    “查询返回的游标仅在同一查询中有效。当您从[我的步骤1,JF]中的仅键查询切换到[我的步骤2,JF]中的仅非键查询时,游标不再适用…”


    “如果您的目标是将结果集拆分为大小相似的块,那么您可能想看看[现在是版本1beta3,JF]。”

    Ed Davisson,一位从事谷歌数据存储客户端API工作的谷歌工程师。他提供了问题的根本原因和建议的解决方案

    他说:

    “查询返回的游标仅在同一查询中有效。当您从仅键查询[在我的步骤1中,JF]切换到非仅键查询[在我的步骤2中,JF]时,光标不再适用


    “如果您的目标是将结果集拆分为大小相似的块,那么您可能需要查看[现在是版本1beta3,JF]。”

    谢谢,这可能会奏效。但缓慢的部分是实际的查询,而不是每个实体的后期处理